Last active
June 4, 2019 19:35
-
-
Save sickel/9d6ff3b2ddd8ee89d873bb4b82ec5a73 to your computer and use it in GitHub Desktop.
A python deamon that spins of an extra thread and acts on signals
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Concept of daemon that spins of an extra thread and can be controlled by signals | |
# | |
# I have rewritten the script slightly after I did this log. So some output has changed a bit, | |
# the signals are still the same | |
# | |
# This has to be run with python3 | |
# | |
# Developed and tested on debian 9.9 - all modules installed with apt | |
# | |
# morten@latlon:/home/disk0/m/GardenController$ sudo tail -f /var/log/messages & | |
# morten@latlon:/home/disk0/m/GardenController$ python3 controller_daemon.py && ps -u morten | grep py | |
# 26808 ? 00:00:00 python3 | |
# morten@latlon:/home/disk0/m/GardenController$ Jun 2 20:42:15 latlon controller_daemon.py: starting up | |
# Jun 2 20:42:15 latlon controller_daemon.py: Thread started | |
# Jun 2 20:42:15 latlon controller_daemon.py: Thread still active | |
# Jun 2 20:42:30 latlon controller_daemon.py: Thread still active | |
# morten@latlon:/home/disk0/m/GardenController$ kill -SIGUSR1 26808 | |
# Jun 2 20:42:40 latlon controller_daemon.py: sending message to thread | |
# Jun 2 20:42:45 latlon controller_daemon.py: Thread got it | |
# Jun 2 20:42:45 latlon controller_daemon.py: Thread still active | |
# morten@latlon:/home/disk0/m/GardenController$ kill -SIGUSR2 `cat /tmp/controller.pid` | |
# Jun 2 20:42:51 latlon controller_daemon.py: Got it! | |
# morten@latlon:/home/disk0/m/GardenController$ kill -SIGUSR1 26808 | |
# Jun 2 20:42:55 latlon controller_daemon.py: sending message to thread | |
# Jun 2 20:43:00 latlon controller_daemon.py: Thread got it | |
# Jun 2 20:43:00 latlon controller_daemon.py: Thread still active | |
# morten@latlon:/home/disk0/m/GardenController$ kill -SIGTERM 26808 | |
# Jun 2 20:43:20 latlon controller_daemon.py: Starting to exit | |
# Jun 2 20:43:20 latlon controller_daemon.py: starting to end process | |
# Jun 2 20:43:20 latlon controller_daemon.py: ending process | |
# Jun 2 20:43:30 latlon controller_daemon.py: Ending thread | |
# Jun 2 20:43:30 latlon controller_daemon.py: Finished | |
# After a signal is sent, it may take up to 5 secs before it is processed by the main deamon thread and up to 15 secs | |
# afterwards for the subthread. - Nothing happens during the time.sleep()s. To get the code more responsive, it is | |
# possible to have short sleeps and use some other checks to see if the time is due to do whatever is to be done, but this is | |
# meant to be an as simple as possible example. | |
# | |
import daemon | |
import daemon.pidfile | |
import time | |
import signal | |
import threading | |
import os | |
import syslog | |
EXITDAEMON=False | |
MSGTHREAD=False | |
def runthread(evtexit,evtmsg): | |
syslog.syslog(syslog.LOG_NOTICE,"Thread started") | |
while True: | |
if evtexit.isSet(): | |
syslog.syslog(syslog.LOG_NOTICE,"Ending thread") | |
return() | |
if evtmsg.isSet(): | |
syslog.syslog(syslog.LOG_NOTICE,"Thread got it") | |
syslog.syslog(syslog.LOG_NOTICE,"Thread still active") | |
time.sleep(15) | |
def do_work(): | |
global MSGTHREAD | |
global EXITDAEMON | |
syslog.syslog(syslog.LOG_NOTICE,"starting up") | |
stopthread=threading.Event() | |
msgthread=threading.Event() | |
trd=threading.Thread(target=runthread,args = (stopthread,msgthread, )) | |
trd.start() | |
while True: | |
with open("/tmp/current_time.txt", "w") as f: | |
f.write("The time is now " + time.ctime()) | |
if MSGTHREAD: | |
msgthread.set() | |
syslog.syslog(syslog.LOG_NOTICE,"sending message to thread") | |
MSGTHREAD=False | |
if EXITDAEMON: | |
syslog.syslog(syslog.LOG_NOTICE,"starting to end process ") | |
break | |
time.sleep(5) | |
# Will get here after a break caused by EXITDEAMON being true | |
syslog.syslog(syslog.LOG_NOTICE,"ending process") | |
stopthread.set() # tells the thread to finish its business | |
trd.join() # ends thread | |
syslog.syslog(syslog.LOG_NOTICE,"Finished") | |
def receiveSignal(signalNumber, frame): | |
syslog.syslog("Got it!") | |
def shutdown(signum,frame): | |
global EXITDAEMON | |
EXITDAEMON=True | |
syslog.syslog(syslog.LOG_NOTICE,"Ready to exit") | |
def msgthread(signum,frame): | |
global MSGTHREAD | |
MSGTHREAD=True | |
syslog.syslog(syslog.LOG_NOTICE,"Will send message to thread") # This was added after I did the log at the top | |
def run(): | |
with daemon.DaemonContext(signal_map={ | |
signal.SIGTERM: shutdown, | |
signal.SIGUSR2: receiveSignal, | |
signal.SIGUSR1: msgthread | |
},pidfile=daemon.pidfile.PIDLockFile('/tmp/controller.pid')): | |
# If making a daemon that is to be run as root, put the pidfile in /var/run, or maybe the users home dir | |
do_work() | |
if __name__ == "__main__": | |
run() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment