What is the proper way to shutdown tornado? I'm using the pre-fork feature. Which pid should I send the SIGINT signals to? Upon catching this signal, I'd like the server to stop accepting all new requests and gracefully wait for all the current request handlers in the event loop to finish.
--
You received this message because you are subscribed to the Google Groups "Tornado Web Server" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python-tornad...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
I don't particularly care about the speed of restart. I can wait something like 5 minutes for each process to shutdown. If I simply send SIGINT to every process, then each of them will exit gracefully (ie. wait for all requests to finish) without requiring me needing to do anything special on my end? Righ now I just call tornado.ioloop.IOLoop.instance().stop() for each process.
I see. I will try that out.Also, should TCPServer.stop() be invoked if and only if tornado.process.task_id() == None? It looks like having the parent process stop() is all thats required to stop requests being forwarded to the children after some experimentation.
It would be nice to expose a way in process.py to look up the pid, given a task id, or perhaps expose the children dict directly. I would be happy to submit a pull request if this makes sense.
def stop_children(sig, frame):print('-> stopping children', process2.task_id())# stop accepting new requestsserver.stop()# wait for all the locks to expiredeadline = time.time() + 10io_loop = tornado.ioloop.IOLoop.instance()def stop_loop():now = time.time()if now < deadline and app.db.zrange('locks', 0, -1):io_loop.add_timeout(now + 1, stop_loop)else:app.shutdown()stop_loop()vs (using add_callback_from_signal):
Thanks Ben, I've taken your suggestions into account and modified the gist:Two changes I made:1. Made fork_processes stop naturally, and catching a SystemExit to shutdown gracefully.2. Got rid of blocking sleep and replaced it with add_timeout (I assume it is safe to invoke from signal handlers, even though it will be using the same stack_context as the handlers) since docs mention using it explicitly. I could adapt it to use io_loop.add_callback_from_signal but I'm not sure which version is preferred. Eg:
def stop_children(sig, frame):print('-> stopping children', process2.task_id())# stop accepting new requestsserver.stop()# wait for all the locks to expiredeadline = time.time() + 10io_loop = tornado.ioloop.IOLoop.instance()def stop_loop():now = time.time()if now < deadline and app.db.zrange('locks', 0, -1):io_loop.add_timeout(now + 1, stop_loop)else:app.shutdown()stop_loop()vs (using add_callback_from_signal):def stop_children(sig, frame):print('-> stopping children', tornado.process.task_id())# stop accepting new requestsserver.stop()# wait for all the locks to expiredeadline = time.time() + 10def stop_loop():if time.time() < deadline and app.db.zrange('locks', 0, -1):time.sleep(1)
Sorry I meant that add_timeout is generally used for sleeping.> Where do the docs mention that? add_timeout is definitely not safe for use from a signal handler (and in general you should assume that anything that interacts with any non-local object is not safe from a signal handler unless documented otherwise).> The sleep is still a problem in this version. You must use add_callback_from_signal to schedule something like your first stop_loop function on the IOLoop, which will in turn use add_timeout instead of sleep.Why is it safe to invoke add_timeout after calling it from a callback inside add_callback_from_signal as opposed to just invoking directly?
Also, do you mean something like this instead?