2013-12-17 37 views
4

我在基于Gevent的Python中编写了一个简单的守护进程。守护进程在它存在之前需要进行一些清理,因此它必须能够处理TERM信号,对其进行清理并优雅地退出。在一个不基于Gevent的单线程守护进程中,我使用Python的信号模块为TERM信号设置了一个信号处理程序。信号处理程序抛出一个用户定义的异常,称为TermSignal。守护进程的主线程可以捕获TermSignal异常,进行清理并退出。在基于Gevent的应用程序中捕获TERM信号

当我试图在基于Gevent的守护程序中实现它时,此解决方案没有按预期工作。守护进程有一个主要的greenlet,在工人greenlets上调用joinalljoinall调用被封装在try/except块中,该块捕获KeyboardInterrupt,它允许守护进程在其不进行守护进程运行时执行其清理操作。但是,当我实现上述解决方案并向进程发送TERM信号时,我可以在控制台窗口中看到其中一个worker greenlet引发了TermSignal异常,而不是主greenlet。这个未捕获的异常并没有影响主greenlet,尽管面对我称为joinallraise_error参数设置为True。结果是由于例外情况,其中一个工人小程序崩溃,但守护进程根本没有退出。

回答

7

当我做了一些搜索后,我找到了解决方案。正如here所提到的,Gevent的猴子修补不会修补Python内置的signal.signal函数。为了让我的解决方案起作用,主greenlet必须调用gevent.signal而不是signal.signal以设置处理程序。此外,gevent.signal预计处理函数不接受参数,不像signal.signal,它需要处理函数接受2个参数。由于我不关心这些论点反正,我改变了我的任期处理程序是这样的:

def _term_handler(*_): 
    raise TermSignal() 

使同项手柄可以在GEVENT应用和常规的Python应用程序中使用。尽管可以在两种情况下使用相同的处理程序,但需要通过相应功能进行设置(signal.signalgevent.signal