I have a single threaded Python 2.7 daemon/service running on Debian. I have some critical cleanup code that disables certain hardware features.
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()
This looks paranoid, and I also don't like calling the cleanup code so many times. Right now it looks like cleanup is called 3 or 4 times on a SIGTERM
.
Is there one single way to prevent_the_apocalypse
exactly once in all possible exit conditions?
Writing a correct daemon in Python is hard. In fact, it's hard in any language. PEP 3143 explains the issues.
The daemon
module wraps up most of the details so you don't have to get them right. If you use that, it becomes very easy to add cleanup code.
One option is to just subclass daemon.DaemonContext
and put it there. For example:
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()
The daemon
module already sets up the signal handlers so that they do what you've configured them to do, but without skipping the close
method. (The close
will be run exactly once—in the context's __exit__
, in an atexit
method, or possibly elsewhere, as appropriate.)
If you want something more complicated, where some signals skip close
and others don't, instead of subclassing, just set its signal_map
appropriately.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With