IOLoop 的 Tornado 优雅关闭
Tornado graceful shutdown of IOLoop
我正在使用以下代码正常关闭我的 tornado 应用程序(摘自 https://gist.github.com/wonderbeyond/d38cd85243befe863cdde54b84505784):
def sig_handler(servers, sig, frame):
io_loop = tornado.ioloop.IOLoop.instance()
def stop_loop(deadline):
now = time.time()
if now < deadline and (io_loop._callbacks or io_loop._timeouts):
logging.info('Waiting for next tick')
print("CALL BACKS")
print(io_loop._callbacks)
print("TIMEOUTS")
print(io_loop._timeouts)
io_loop.add_timeout(now + 1, stop_loop, deadline)
else:
io_loop.stop()
logging.info("Shutting down.")
def shutdown():
logging.info("Stopping http servers")
# servers is a list of servers to stop
for s in servers:
s.stop()
logging.info("Will shutdown in %s seconds ...",
MAX_WAIT_SEC_BEFORE_SHUTDOWN)
stop_loop(time.time() + MAX_WAIT_SEC_BEFORE_SHUTDOWN)
logging.warning("Caught signal: %s", sig)
io_loop.add_callback_from_signal(shutdown)
我将 MAX_WAIT_SEC_BEFORE_SHUTDOWN 设置为 10 秒。即使在关闭 http 服务器后,每次关闭服务器也需要整整 10 秒。我注意到 io_loop._timeouts
列表中总是有项目,例如:
[<tornado.ioloop._Timeout object at 0x106b90408>, <tornado.ioloop._Timeout object at 0x106b904c8>, ...]
io_loop._timeouts
中有哪些项目?我应该期望这是一个空列表还是我没有停止我应该拥有的东西?
这个关机程序正常吗?谁能推荐其他代码?
停止 Tornado HTTPServer
不会关闭所有现有连接,它只会阻止服务器接受新连接。有一个undocumented close_all_connections
method,但它不区分空闲连接和当前正在处理请求的连接,因此不适合在优雅关闭中使用。当前没有任何方法可以在所有连接空闲时关闭它们。
每个空闲连接在 IOLoop 上保持超时(如果空闲时间过长,连接将关闭,尽管默认值为一小时。将 idle_connection_timeout=
传递给 HTTPServer
构造函数来改变这个)。此外,Tornado 或其他库的其他功能也可能会产生超时(在 Tornado 本身中,curl_httpclient
和 autoreload
都会产生总是 运行 的超时),因此您通常不能假设未决超时的数量将永远达到零。
一般来说,我建议只是无条件地等待 MAX_WAIT_SEC_BEFORE_SHUTDOWN
,而不是试图确定是否可以安全地尽快关闭。如果您确实想确定所有挂起的操作何时完成,那么最好自己记录挂起操作的数量(对于您认为合适的 "operation" 的任何定义),而不是试图从实现细节中推断这一点IOLoop
。
我正在使用以下代码正常关闭我的 tornado 应用程序(摘自 https://gist.github.com/wonderbeyond/d38cd85243befe863cdde54b84505784):
def sig_handler(servers, sig, frame):
io_loop = tornado.ioloop.IOLoop.instance()
def stop_loop(deadline):
now = time.time()
if now < deadline and (io_loop._callbacks or io_loop._timeouts):
logging.info('Waiting for next tick')
print("CALL BACKS")
print(io_loop._callbacks)
print("TIMEOUTS")
print(io_loop._timeouts)
io_loop.add_timeout(now + 1, stop_loop, deadline)
else:
io_loop.stop()
logging.info("Shutting down.")
def shutdown():
logging.info("Stopping http servers")
# servers is a list of servers to stop
for s in servers:
s.stop()
logging.info("Will shutdown in %s seconds ...",
MAX_WAIT_SEC_BEFORE_SHUTDOWN)
stop_loop(time.time() + MAX_WAIT_SEC_BEFORE_SHUTDOWN)
logging.warning("Caught signal: %s", sig)
io_loop.add_callback_from_signal(shutdown)
我将 MAX_WAIT_SEC_BEFORE_SHUTDOWN 设置为 10 秒。即使在关闭 http 服务器后,每次关闭服务器也需要整整 10 秒。我注意到 io_loop._timeouts
列表中总是有项目,例如:
[<tornado.ioloop._Timeout object at 0x106b90408>, <tornado.ioloop._Timeout object at 0x106b904c8>, ...]
io_loop._timeouts
中有哪些项目?我应该期望这是一个空列表还是我没有停止我应该拥有的东西?
这个关机程序正常吗?谁能推荐其他代码?
停止 Tornado HTTPServer
不会关闭所有现有连接,它只会阻止服务器接受新连接。有一个undocumented close_all_connections
method,但它不区分空闲连接和当前正在处理请求的连接,因此不适合在优雅关闭中使用。当前没有任何方法可以在所有连接空闲时关闭它们。
每个空闲连接在 IOLoop 上保持超时(如果空闲时间过长,连接将关闭,尽管默认值为一小时。将 idle_connection_timeout=
传递给 HTTPServer
构造函数来改变这个)。此外,Tornado 或其他库的其他功能也可能会产生超时(在 Tornado 本身中,curl_httpclient
和 autoreload
都会产生总是 运行 的超时),因此您通常不能假设未决超时的数量将永远达到零。
一般来说,我建议只是无条件地等待 MAX_WAIT_SEC_BEFORE_SHUTDOWN
,而不是试图确定是否可以安全地尽快关闭。如果您确实想确定所有挂起的操作何时完成,那么最好自己记录挂起操作的数量(对于您认为合适的 "operation" 的任何定义),而不是试图从实现细节中推断这一点IOLoop
。