正确的方法来清理Python服务 - atexit,signal,try / finally

时间:2013-10-09 17:45:13

标签: python daemon

我在Debian上运行单线程Python 2.7守护程序/服务。我有一些禁用某些硬件功能的关键清理代码。

import sys
import atexit
import signal
from my_job import give_high_fives
from my_cleanup import prevent_the_apocalypse

atexit.register(prevent_the_apocalypse)
signal.signal(signal.SIGTERM, prevent_the_apocalypse)
signal.signal(signal.SIGHUP, prevent_the_apocalypse)
try:
    while True:
        give_high_fives()
finally:
    prevent_the_apocalypse()

这看起来很偏执,我也不喜欢多次调用清理代码。现在,看起来清理在SIGTERM上被称为3或4次。

在所有可能的退出条件下,prevent_the_apocalypse只有一种方法可以完成一次吗?

2 个答案:

答案 0 :(得分:6)

在Python中编写正确的守护进程很难。事实上,任何语言都很难。 PEP 3143解释了这些问题。

daemon模块包含了大部分细节,因此您不必将它们弄清楚。如果使用它,则添加清理代码变得非常容易。

一个选项是将daemon.DaemonContext子类化并将其放在那里。例如:

class MyDaemonContext(daemon.DaemonContext):
    def close(self):
        if not self.is_open:
            return
        prevent_the_apocalypse()
        super(MyDaemonContext, self).close()

with MyDaemonContext():
    while True:
        give_high_fives()

daemon模块已经设置了信号处理程序,以便它们执行您已配置的操作,但不会跳过close方法。 (close将在上下文__exit__atexit方法中运行一次,或者可能在其他地方运行。{/ p>

如果你想要更复杂的东西,有些信号会跳过close而其他信号却没有,而不是子类化,只需适当地设置signal_map

答案 1 :(得分:-1)

让您的信号处理程序除了将全局变量设置为true之外什么也不做。然后在主循环中检查该变量,如果它是真的则跳出,在退出时运行清理处理程序。