我用基于 Gevent 的 Python 编写了一个简单的守护进程。守护进程在存在之前需要做一些清理,因此它有必要处理 TERM 信号,执行清理并优雅地退出。在不基于 Gevent 的单线程守护进程中,我使用 Python 的信号模块为 TERM 信号设置信号处理程序。信号处理程序抛出一个用户定义的异常,称为 TermSignal
。守护进程的主线程可以捕获 TermSignal 异常,进行清理并退出。
当我尝试在基于 Gevent 的守护进程中实现该解决方案时,它没有按预期工作。守护进程有一个主要的 greenlet,它调用 worker greenlet 上的 joinall
。 joinall
调用包含在 try/except block 中,该 block 捕获 KeyboardInterrupt
,这允许守护进程在运行时执行清理,而无需守护进程。但是,当我实现上述解决方案并向进程发送 TERM 信号时,我可以在控制台窗口中看到其中一个工作人员 greenlet 引发了 TermSignal
异常,而不是主 greenlet。尽管我调用 joinall
并将 raise_error
参数设置为 True
,但这个未捕获的异常并没有传播到主 greenlet。结果是其中一个 worker greenlets 由于异常而崩溃,但是守护进程根本没有退出。
最佳答案
经过一番搜索,我找到了解决方案。如前所述 here , Gevent 的猴子补丁不会给 Python 内置的 signal.signal
函数打补丁。为了让我的解决方案起作用,主要的 greenlet 必须调用 gevent.signal
而不是 signal.signal
来设置处理程序。此外,gevent.signal
需要不接受任何参数的处理函数,而 signal.signal
需要接受 2 个参数的处理函数。因为无论如何我都不关心这些参数,所以我将术语处理程序更改为如下所示:
def _term_handler(*_):
raise TermSignal()
以便在 Gevent 应用程序和常规 Python 应用程序中可以使用相同的术语 handle。尽管在两种情况下都可以使用相同的处理程序,但需要通过适当的函数(signal.signal
或 gevent.signal
)进行设置
关于python - 在基于 Gevent 的应用程序中捕获 TERM 信号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20630142/