如何从 mod_wsgi 正常关闭应用程序
How to do graceful application shutdown from mod_wsgi
所以我有一个 Flask 应用程序,我已经 运行 在 Flask 的内置服务器上,并准备将其移至生产环境。此应用程序管理多个子进程。到目前为止,我一直在使用信号处理正常关闭。特别是,我使用的一种关闭模式是向 flask 服务器发送 SIGHUP 导致应用程序将该信号传播给它的子级(这样他们就可以正常关闭),然后让应用程序进程关闭。
在生产中,我们计划使用 mod_wsgi。我读过 wsgi applications really shouldn't be handling signals。
所以我的问题是,我应该如何使用此设置实现以下行为?:
- 当 apache 收到 SIGTERM 时,它会在终止 wsgi 守护进程之前通知它们
- wsgi 守护进程有机会在关闭前自行进行一些清理工作
将 SIGTERM
发送到 Apache 父进程,这就是现在发生的事情。
发生的事情是,当 Apache 父进程收到 SIGTERM
时,它又将 SIGTERM
发送到其所有子工作进程,以及托管的 mod_wsgi 守护进程如果使用守护进程模式。这些子进程将停止接受新请求,并在子进程被强行关闭之前最多有 3 秒的时间来完成现有请求。
因此 SIGTERM
的默认行为是允许一些时间来完成请求,但是长时间的 运行ning 请求将不允许阻止服务器完全关闭。等待子进程关闭的时间不可配置,固定为 3 秒。
您可以发送 SIGWINCH
信号代替 SIGTERM
。这将导致 Apache 正常停止,但这有问题。
在 SIGWINCH
的情况下会发生什么,Apache 将再次发送 SIGTERM
到它的子工作进程,但它不会在 3 秒后强行终止进程,而是允许它们到 运行,直到至少完成所有活动请求。
一个问题是没有故障保险。如果这些请求永远不会完成,我知道没有超时会看到子工作进程被强制关闭。因此,您的服务器可能会在关机时挂起。
第二个问题是 Apache 仍然会在 3 秒后强行终止托管的 mod_wsgi 守护进程,并且没有(或者上次没有)覆盖 Apache 管理这些进程的方式进程,以便更优雅地关闭托管守护进程。所以优雅的停止信号在使用守护进程模式时不会改变任何东西。
最接近优雅停止的是在前端路由层,将新流量从 Apache 实例转移开。然后通过主机 运行ning Apache 中的某种机制触发一个脚本,该脚本将 SIGUSR2
发送到 mod_wsgi 守护进程。假设您已将守护进程组上的 graceful-timeout
选项设置为足够的故障保护,如果所有活动请求完成,这将导致守护进程退出。如果超时到期,那么它将进入正常的进程关闭序列,即不接受来自 Apache 子工作进程的新请求,并且在 shutdown-timeout
(默认 5 秒)触发后,如果请求仍未完成,则进程是强行关机。
在这种情况下,它实际上并没有关闭进程,而是导致它们退出,这将导致它们被替换,因为我们没有告诉整个 Apache 停止,而只是告诉 mod_wsgi 守护进程进行正常重启。在这种情况下,除非您监视守护进程集并知道它们何时全部重新启动,否则您没有明确的迹象表明它们已全部完成,然后可以关闭整个 Apache 实例。
所以做起来有点繁琐,任何服务器都很难以一种通用的方式做到这一点,因为什么是合适的实际上还取决于托管应用程序及其要求。
问题是您是否真的需要这样做。无论如何请求都不可避免地会失败,用户必须处理这个问题,因此在重启时中断少数请求并不是什么大问题。应用程序有什么特别之处需要您设置更高的标准并尝试确保零请求中断?
所以我有一个 Flask 应用程序,我已经 运行 在 Flask 的内置服务器上,并准备将其移至生产环境。此应用程序管理多个子进程。到目前为止,我一直在使用信号处理正常关闭。特别是,我使用的一种关闭模式是向 flask 服务器发送 SIGHUP 导致应用程序将该信号传播给它的子级(这样他们就可以正常关闭),然后让应用程序进程关闭。
在生产中,我们计划使用 mod_wsgi。我读过 wsgi applications really shouldn't be handling signals。
所以我的问题是,我应该如何使用此设置实现以下行为?:
- 当 apache 收到 SIGTERM 时,它会在终止 wsgi 守护进程之前通知它们
- wsgi 守护进程有机会在关闭前自行进行一些清理工作
将 SIGTERM
发送到 Apache 父进程,这就是现在发生的事情。
发生的事情是,当 Apache 父进程收到 SIGTERM
时,它又将 SIGTERM
发送到其所有子工作进程,以及托管的 mod_wsgi 守护进程如果使用守护进程模式。这些子进程将停止接受新请求,并在子进程被强行关闭之前最多有 3 秒的时间来完成现有请求。
因此 SIGTERM
的默认行为是允许一些时间来完成请求,但是长时间的 运行ning 请求将不允许阻止服务器完全关闭。等待子进程关闭的时间不可配置,固定为 3 秒。
您可以发送 SIGWINCH
信号代替 SIGTERM
。这将导致 Apache 正常停止,但这有问题。
在 SIGWINCH
的情况下会发生什么,Apache 将再次发送 SIGTERM
到它的子工作进程,但它不会在 3 秒后强行终止进程,而是允许它们到 运行,直到至少完成所有活动请求。
一个问题是没有故障保险。如果这些请求永远不会完成,我知道没有超时会看到子工作进程被强制关闭。因此,您的服务器可能会在关机时挂起。
第二个问题是 Apache 仍然会在 3 秒后强行终止托管的 mod_wsgi 守护进程,并且没有(或者上次没有)覆盖 Apache 管理这些进程的方式进程,以便更优雅地关闭托管守护进程。所以优雅的停止信号在使用守护进程模式时不会改变任何东西。
最接近优雅停止的是在前端路由层,将新流量从 Apache 实例转移开。然后通过主机 运行ning Apache 中的某种机制触发一个脚本,该脚本将 SIGUSR2
发送到 mod_wsgi 守护进程。假设您已将守护进程组上的 graceful-timeout
选项设置为足够的故障保护,如果所有活动请求完成,这将导致守护进程退出。如果超时到期,那么它将进入正常的进程关闭序列,即不接受来自 Apache 子工作进程的新请求,并且在 shutdown-timeout
(默认 5 秒)触发后,如果请求仍未完成,则进程是强行关机。
在这种情况下,它实际上并没有关闭进程,而是导致它们退出,这将导致它们被替换,因为我们没有告诉整个 Apache 停止,而只是告诉 mod_wsgi 守护进程进行正常重启。在这种情况下,除非您监视守护进程集并知道它们何时全部重新启动,否则您没有明确的迹象表明它们已全部完成,然后可以关闭整个 Apache 实例。
所以做起来有点繁琐,任何服务器都很难以一种通用的方式做到这一点,因为什么是合适的实际上还取决于托管应用程序及其要求。
问题是您是否真的需要这样做。无论如何请求都不可避免地会失败,用户必须处理这个问题,因此在重启时中断少数请求并不是什么大问题。应用程序有什么特别之处需要您设置更高的标准并尝试确保零请求中断?