我实现了一个使用
python-daemon
进行守护进程的 Python 守护进程。
一个精简的最小示例是:
import daemon
import daemon.pidfile
import threading
import syslog
import signal
class Runner:
def run(self):
syslog.syslog("Running something")
def scheduleNextRun(self):
self.run()
self.timer = threading.Timer(3, self.scheduleNextRun)
self.timer.start()
def terminate(self, signum, frame):
syslog.syslog("Received {}".format(signal.Signals(signum).name))
if self.timer:
syslog.syslog("Stopping the timer")
self.timer.cancel()
syslog.syslog("Will now terminate")
def setup():
runner = Runner()
signal.signal(signal.SIGTERM, runner.terminate)
signal.signal(signal.SIGINT, runner.terminate)
runner.scheduleNextRun()
with daemon.DaemonContext(pidfile = daemon.pidfile.PIDLockFile("/var/run/test.pid")):
setup()
守护进程启动并写入系统日志,并且在收到 SIGTERM 时也会关闭。但是,没有创建 pidfile。
我在寻找解决方案时尝试了不同的方法来调用
DaemonContext
,但都没有导致创建 pidfile:
两者
...
import lockfile
...
with daemon.DaemonContext(pidfile = lockfile.FileLock("/var/run/test.pid")):
...
并且(使用
https://github.com/bmhatfield/python-pidfile中的
pidfile.py
)
...
from pidfile import PidFile
...
with daemon.DaemonContext(pidfile = PidFile("/var/run/test.pid")):
...
工作,但我从未得到 pidfile。
获取行为良好的守护进程必须创建的 pid 文件的正确方法是什么?
好吧,现在我知道会发生什么了;-)
就像
DaemonContext
超出范围一样简单。 pidfile 实际上已创建,但又立即被删除。
我通过使用
threading.Event
解决了这个问题:
Runner
在其Event
功能中添加了__init__
:
self.finished = threading.Event()
并将其设置为
terminate
:
self.finished.set()
DaemonContext
正在等待:
runner = Runner()
def setup():
signal.signal(signal.SIGTERM, runner.terminate)
signal.signal(signal.SIGINT, runner.terminate)
runner.scheduleNextRun()
with daemon.DaemonContext(pidfile = daemon.pidfile.PIDLockFile("/var/run/test.pid")):
setup()
runner.finished.wait()
这样,主程序就会停留在
DaemonContext
中,直到 Runner
终止,并且 pidfile 就在那里。