Maybe this is a problem in Flask, there is no way to handle disconnection event on the server side.
In Response class, there is a method named "call_on_close", where we can add a function without argument, e.g. on_close(), it will be fired when the response object's close method called, but this doesn't happen when I call EventSource.close() from the client side in Javascript.
code on server side:
from flask import Response r = Response(stream(), ...) r.call_on_close(on_close) return r def on_close(): print "response is closed!" def stream(): ... # subscribe to redis for message in pubsub.listen(): .... yield 'data: %s\n\n' % message
on client side: add unload handler to page with SSE
$(window).unload( function() { sse.close(); } }
Anything is wrong?
Any suggestions or solution with code is appreciated!
Thanks in advance!
The generator receives a GeneratorExit
exception, and that's when you know it will exit. For example:
def stream(): try: i = 0 while True: yield 'Hello {}!'.format(i) i += 1 time.sleep(1) finally: # Called after a GeneratorExit, cleanup here i = 0 @app.route('/messages') def messages(): return Response(stream(), content_type='text/event-stream')
Will yield a infinite stream of "Hello!"
, and you will know when it's done, where you can run cleanup code. If your generator blocks the thread, it will need to be unblocked in some way (maybe pushing a dummy item) so that the generator can be closed.
I've had a similar problem with Rails Live Controllers. The problem is that the framework doesn't seem to detect that the connection is closed until it attempts to send an Event to the client.
One approach is to send periodic "heartbeat" events to the client. I'm presently using this successfully on my Rails project with an interval of 60 seconds. I have a separate thread that "emits" these heartbeats into Redis, that my controller has subscribed to.
An alternative to the threaded approach, is to wrap the Redis pubsub block with a timeout (again, say 60 seconds). And then send the heartbeat event to the client - followed by another pubsub call. The downside to this approach, is you may miss an event while you're not subscribed.
There's more on the threading approach here: Redis + ActionController::Live threads not dying
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With