Skip to content

Instantly share code, notes, and snippets.

@mikelikespie
Created March 4, 2011 22:19
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save mikelikespie/855808 to your computer and use it in GitHub Desktop.
Save mikelikespie/855808 to your computer and use it in GitHub Desktop.
Graceful tornado http server shutdown
class MyHTTPServer(tornado.httpserver.HTTPServer):
_stopped = False
def _quit_if_ioloop_is_empty(self):
ioloop = tornado.ioloop.IOLoop.instance()
if len(ioloop._handlers) <= 1:
logger.info("Graceful shutdown complete. Exiting!")
exit(0)
else:
logger.info("Waiting for ioloop to be empty. has %d handlers left" % len(ioloop._handlers))
def _setup_worker_handlers(self):
def quick_shutdown_handler(signum, frame):
logger.warning("worker received signal %d. exiting immediately" % signum)
exit(0)
def graceful_shutdown_handler(signum, frame):
logger.warning("worker received signal %d. gracefully shutting down" % signum)
if not self._stopped:
self.no_keep_alive = True
self._stopped = True
self.stop()
max_wait_seconds = 100
logger.info("Waiting for all connections to finish or %d seconds to pass (setting SIGALRM)" % max_wait_seconds)
signal.signal(signal.SIGALRM, quick_shutdown_handler)
signal.alarm(max_wait_seconds)
pc = tornado.ioloop.PeriodicCallback(self._quit_if_ioloop_is_empty, 100, io_loop=tornado.ioloop.IOLoop.instance())
pc.start()
else:
logger.warning("worker received signal %d. graceful shutdown has already begun" % signum)
signal.signal(signal.SIGINT, quick_shutdown_handler)
signal.signal(signal.SIGTERM, quick_shutdown_handler)
signal.signal(signal.SIGQUIT, graceful_shutdown_handler)
def _setup_master_handlers(self):
def quick_shutdown_handler(signum, frame):
logger.warning("master received signal %d. Shutting down worker quickly" % signum)
if self.child_pid:
os.kill(self.child_pid, signum)
os.waitpid(self.child_pid, 0)
logger.warning("Child shut down successfully")
def graceful_shutdown_handler(signum, frame):
logger.warning("master received signal %d. Shutting down worker gracefully" % signum)
if self.child_pid:
os.kill(self.child_pid, signum)
logger.warning("master process exiting and detatching child")
exit(0)
signal.signal(signal.SIGINT, quick_shutdown_handler)
signal.signal(signal.SIGTERM, quick_shutdown_handler)
signal.signal(signal.SIGQUIT, graceful_shutdown_handler)
def start(self, num_processes=1):
if num_processes != 1:
logger.error("We can only support one process. Setting to 1")
num_processes = 1
self.child_pid = os.fork()
if not self.child_pid:
self._setup_worker_handlers()
tornado.httpserver.HTTPServer.start(self, num_processes)
else:
self._setup_master_handlers()
logger.info("Waiting on child pid %d" % self.child_pid)
try:
os.waitpid(self.child_pid, 0)
logger.info("Child process appears to have exited")
self.child_pid = None
except OSError, e:
if e.errno != 4:
raise
finally:
exit(0)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment