I'm using long polling for a chat with gevent. I'm using Event.wait() when waiting for new messages to be posted on the chat.
I would like to handle the occasion a client disconnects with some functiona开发者_高级运维lity:
e.g. Return "client has disconnected" as a message for other chat users
Is this possible? =)
According to the WSGI PEP, if your app returns an iterator with a close() method, the server should call that at the end of the request. Here's an example:
"""
Run this script with 'python sleepy_app.py'. Then try connecting to the server
with curl:
curl -N http://localhost:8000/
You should see a counter printed in your terminal, incrementing once every
second.
Hit Ctrl-C on the curl window to disconnect the client. Then watch the
server's output. If running with a WSGI-compliant server, you should see
"SLEEPY CONNECTION CLOSE" printed to the terminal.
"""
class SleepyApp(object):
def __init__(self, environ, start_response):
self.environ = environ
self.start_response = start_response
def __iter__(self):
self.start_response('200 OK', [('Content-type', 'text/plain')])
# print out one number every 10 seconds.
import time # imported late for easier gevent patching
counter = 0
while True:
print "SLEEPY", counter
yield str(counter) + '\n'
counter += 1
time.sleep(1)
def close(self):
print "SLEEPY CONNECTION CLOSE"
def run_gevent():
from gevent.monkey import patch_all
patch_all()
from gevent.pywsgi import WSGIServer
server = WSGIServer(('0.0.0.0', 8000), SleepyApp)
print "Server running on port 0.0.0.0:8000. Ctrl+C to quit"
server.serve_forever()
if __name__ == '__main__':
run_gevent()
However, there's a bug in Python's wsgiref implementation (and in the Django dev server that inherits from it) that prevents close() from being called on mid-stream client disconnects. So avoid wsgiref and the Django dev server for this case.
Note also that close() won't be fired immediately when the client disconnects. It'll happen when you try to write some message to the client and fail because the connection isn't there anymore.
This depends on which WSGI server you use. AFAIK gevent.wsgi will not notify your handler in any way when the client closes the connection, because libevent-http does not do that. However, with gevent.pywsgi it should be possible. You'll probably need to start an additional greenlet to monitor the socket condition and somehow notify the greenlet that runs the handler, e.g. by killing it. I could be missing an easier way to do this though.
This is a total stab in the dark as I've never used gevent but wouldn't a client disconnect simply be when the socket is closed. So maybe something like this would work:
if not Event.wait():
# Client has disconnected, do your magic here!
return Chat({'status': 'client x has disconnected'})
精彩评论