Added support for max_requests for Tornado workers, and support for

disabling x_forwarded_for_header.
This commit is contained in:
Mazdak Rezvani 2012-03-13 11:34:14 -04:00 committed by benoitc
parent 8546b766c0
commit 5d4fc56dcb

View File

@ -10,20 +10,20 @@ try:
import tornado.web import tornado.web
except ImportError: except ImportError:
raise RuntimeError("You need tornado installed to use this worker.") raise RuntimeError("You need tornado installed to use this worker.")
from tornado.httpserver import HTTPServer import tornado.httpserver
from tornado.ioloop import IOLoop, PeriodicCallback from tornado.ioloop import IOLoop, PeriodicCallback
from tornado.wsgi import WSGIContainer from tornado.wsgi import WSGIContainer
from gunicorn.workers.base import Worker from gunicorn.workers.base import Worker
from gunicorn import __version__ as gversion from gunicorn import __version__ as gversion
class TornadoWorker(Worker): class TornadoWorker(Worker):
@classmethod @classmethod
def setup(cls): def setup(cls):
web = sys.modules.pop("tornado.web") web = sys.modules.pop("tornado.web")
old_clear = web.RequestHandler.clear old_clear = web.RequestHandler.clear
def clear(self): def clear(self):
old_clear(self) old_clear(self)
self._headers["Server"] += " (Gunicorn/%s)" % gversion self._headers["Server"] += " (Gunicorn/%s)" % gversion
@ -34,8 +34,16 @@ class TornadoWorker(Worker):
super(TornadoWorker, self).handle_quit(sig, frame) super(TornadoWorker, self).handle_quit(sig, frame)
self.ioloop.stop() self.ioloop.stop()
def handle_request(self):
self.nr += 1
if self.alive and self.nr >= self.max_requests:
self.alive = False
self.log.info("Autorestarting worker after current request.")
self.ioloop.stop()
def watchdog(self): def watchdog(self):
self.notify() if self.alive:
self.notify()
if self.ppid != os.getppid(): if self.ppid != os.getppid():
self.log.info("Parent changed, shutting down: %s", self) self.log.info("Parent changed, shutting down: %s", self)
@ -44,6 +52,7 @@ class TornadoWorker(Worker):
def run(self): def run(self):
self.socket.setblocking(0) self.socket.setblocking(0)
self.ioloop = IOLoop.instance() self.ioloop = IOLoop.instance()
self.alive = True
PeriodicCallback(self.watchdog, 1000, io_loop=self.ioloop).start() PeriodicCallback(self.watchdog, 1000, io_loop=self.ioloop).start()
# Assume the app is a WSGI callable if its not an # Assume the app is a WSGI callable if its not an
@ -52,13 +61,30 @@ class TornadoWorker(Worker):
if not isinstance(app, tornado.web.Application): if not isinstance(app, tornado.web.Application):
app = WSGIContainer(app) app = WSGIContainer(app)
server = HTTPServer(app, io_loop=self.ioloop) # Monkey-patching HTTPConnection.finish to count the
if hasattr(server, "add_socket"): # tornado > 2.0 # number of requests being handled by Tornado. This
# will help gunicorn shutdown the worker if max_requests
# is exceeded.
httpserver = sys.modules["tornado.httpserver"]
old_connection_finish = httpserver.HTTPConnection.finish
def finish(other):
self.handle_request()
old_connection_finish(other)
httpserver.HTTPConnection.finish = finish
sys.modules["tornado.httpserver"] = httpserver
server = tornado.httpserver.HTTPServer(app, io_loop=self.ioloop)
if hasattr(server, "add_socket"): # tornado > 2.0
server.add_socket(self.socket) server.add_socket(self.socket)
elif hasattr(server, "_sockets"): # tornado 2.0 elif hasattr(server, "_sockets"): # tornado 2.0
server._sockets[self.socket.fileno()] = self.socket server._sockets[self.socket.fileno()] = self.socket
else: # tornado 1.2 or earlier else: # tornado 1.2 or earlier
server._socket = self.socket server._socket = self.socket
server.no_keep_alive = self.cfg.keepalive <= 0
server.xheaders = bool(self.cfg.x_forwarded_for_header)
server.start(num_processes=1) server.start(num_processes=1)
self.ioloop.start() self.ioloop.start()