I implement a Python daemon that uses python-daemon to daemonize.
A stripped down minimal example would be:
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()
The daemon starts up and writes to syslog, and it also shuts down when receiving SIGTERM. However, no pidfile is created.
I tried different ways to invoke the DaemonContext whilst searching for a solution, but neither lead to a pidfile being created:
Both
...
import lockfile
...
with daemon.DaemonContext(pidfile = lockfile.FileLock("/var/run/test.pid")):
...
and (using pidfile.py from https://github.com/bmhatfield/python-pidfile)
...
from pidfile import PidFile
...
with daemon.DaemonContext(pidfile = PidFile("/var/run/test.pid")):
...
do work, but I never get a pidfile.
What's the correct way to get a pidfile a well-behaved daemon has to create?
Okay, now I know what happens ;-)
It's as simple as the
DaemonContextgoes out of scope. The pidfile actually is created, but it's removed again at once.I solved this by using a
threading.Event:The
Runneradds anEventin it's__init__function:and sets it in
terminate:and the
DaemonContextwaits for it:This way, the main program stays inside the
DaemonContextuntil theRunnerterminates, and the pidfile is there.