How to implement timeout in gevent.WSGIServer ?

691 views
Skip to first unread message

Алексей Я

unread,
Dec 3, 2016, 9:24:46 AM12/3/16
to gevent: coroutine-based Python network library
Hi! Could someone please share a complete mini example of WSGIServer's timeout implementation?

I tried code from this post but it doesn't seem to work => user makes a request and wait forever.
https://github.com/gevent/gevent/issues/649#issuecomment-141439481

Thank you!

Jason Madden

unread,
Dec 3, 2016, 9:39:42 AM12/3/16
to gev...@googlegroups.com
I tested the example code as given in the issue, and it works as described (no individual connection is allowed to last longer than the timeout value, no matter how many HTTP requests it makes). Of course, this requires the WSGI application to be properly gevent-cooperative; if the application doesn't yield to the event loop (for example, it does non-monkey-patched socket IO, or file IO, etc), then the timeout will not be correctly respected.

Note that subclassing the WSGIHandler is a brute-force approach, generally to take only if you cannot control the WSGI application. Most timeout uses will be better served by including it in the WSGI application (again, the bulk of the application must be gevent-cooperative).

Here's a complete example (ignoring most error handling) based on the sample in the issue that shows the handler processing the timeout in a way that doesn't produce a 500 response to the client as the issue comment did. Again, this is tightly coupled to the handler implementation and is not necessarily the recommended way if you have any control over the WSGI application---wrapping it in a decorator function counts as control; if you need to control timeouts for pipelined requests, consider disabling pipelining by setting the Connection:close header:

$ cat test.py
import gevent
from gevent.pywsgi import WSGIHandler, WSGIServer

class MyHandler(WSGIHandler):

def handle(self):
self.timeout = gevent.Timeout.start_new(1)
try:
WSGIHandler.handle(self)
finally:
self.timeout.cancel()

def handle_error(self, t, v, tb):
if v is self.timeout:
self.result = [b"Timeout"]
self.start_response("200 OK", [])
self.process_result()
else:
WSGIHandler.handle_error(self, t, v, tb)


def app(environ, start_response):
gevent.sleep(5)
start_response("200 OK")
return [b"Slept"]

server = WSGIServer(":8080", app, handler_class=MyHandler)
server.serve_forever()
$ python test.py &
[1] 30982
$ http localhost:8080
127.0.0.1 - - [2016-12-03 08:33:32] "GET / HTTP/1.1" 200 82 1.003254
HTTP/1.1 200 OK
Content-Length: 7
Date: Sat, 03 Dec 2016 14:33:32 GMT

Timeout
$

Reply all
Reply to author
Forward
0 new messages