tornado: any way to graceful exit tornado application?
there are many gist show how to graceful exit tornado application like this:
stop_httpserver(http_server)
def try_stop_ioloop():
io_loop = IOLoop.instance()
if io_loop._callbacks or io_loop._timeouts:
io_loop.add_timeout(time.time()+1, try_stop_ioloop)
else:
io_loop.stop()
try_stop_ioloop()
it’s safy to test io_loop._timeouts or _callbacks ? or _timeouts can be ignored?
About this issue
- Original URL
- State: open
- Created 8 years ago
- Reactions: 3
- Comments: 19 (9 by maintainers)
You definitely shouldn’t be looking at
IOLoop._callbacksorIOLoop._timeouts. In addition to being private variables, there’s a good chance that they will never be empty, for reasons that are unimportant (if you usetornado_curl_httpclientthere is always an active timeout). Instead of asking the IOLoop for all activity, you need to decide what activity you care about and exit the server when all of that activity is done.Or you can do what I do and just stop the IOLoop 5 seconds after the stop is requested. This will be enough for any regular request to finish, and if it’s taking longer than 5 seconds you probably want to let it fail anyway. It’s not worth making a more precise measurement to stop in less than 5 seconds.
This seems like a question that is asked frequently enough that an example solution should be included in the user’s guide section of the docs. I would consider adding something to either the Running and deploying section or the Structure section. Ben, which do you think makes the most sense?
Yeah, something like @ploxiln’s approach is what I’d do. I don’t think there have been any noteworthy changes between Tornado 4 and 5 here. It all depends on what “gracefully” means for your application. (One missing piece in the snippet above is that you probably want to signal to your load balancer somehow to stop the incoming traffic).
Here’s how I do it (currently with tornado-4.5.3 but I expect it will work the same with tornado-5.1):
(instead of just
gen.sleep(1)I actually have a global active-request count and atornado.locks.Event()that is set after the last request has finished, but that’s more complicated and more code …)You are right that there are plenty of caveats to how to really do a graceful shutdown depending on the deployment strategy. But for the guide, maybe it would suffice to show a simple example case (such as what you mentioned where you stop the IOLoop 5 seconds later to give requests time to finish) while explaining that this is not the only way, but that it at least works for simple setups. I’ll take a stab at this in the next few days and maybe we can try to iterate through a good solution via a pull request.
We managed to gracefully shutdown tornado by implementing the following steps:
SIGINT/SIGTERMsignalsHTTPServerright away (no more requests are accepted)ioloopwhen all pending requests terminatedSee https://github.com/svaponi/tornado-graceful-shutdown/blob/main/server.py
I came here today to ask the exact same question. For after much reading in SO I came up with this example:
It has two problems:
… which I think means that the
tornado.accesslogger is trying to write after the ioloop has stopped and all sockets to write to gone. Not sure whether a feature or a bug in the logging.Second problem is with AsyncHandler, where request is killed and client receives Remote Disconnected error.
It would be very nice to get an
officialright way of approaching this. I’ll now go and test https://gist.github.com/nicky-zs/6304878 in a real world.