Question

I have python code which runs continuously (collecting sensor data). It is supposed to be launched at boot using start-stop-daemon. However, I'd like to be able to kill the process gracefully, so I've started from the advice in the post How to process SIGTERM signal gracefully? and put my main loop in a separate thread. I'd like to be able to gracefully shut it down both when it is running as a daemon (the start-stop-daemon will send a kill signal) and when I launch it briefly for testing in a terminal myself (me pressing ctrl-c).

However, the signal handler doesn't seem to be called if I kill the process (even without using the thread, the "done (killed)" never ends up in the file I've redirected to). And when I press ctrl-c, the collecting just continues and keeps printing data in the terminal (or to the file I am redirecting to).

What am I doing wrong in the following code?

from threading import Thread
import time, sys, signal

shutdown_flag = False #used for gracefull shutdown 

def main_loop():
    while not shutdown_flag:
        collect_data() # contains some print "data" statements
        time.sleep(5)
    print "done (killed)"

def sighandler(signum, frame):
    print 'signal handler called with signal: %s ' % signum
    global shutdown_flag
    shutdown_flag = True

def main(argv=None):
    signal.signal(signal.SIGTERM, sighandler) # so we can handle kill gracefully
    signal.signal(signal.SIGINT, sighandler) # so we can handle ctrl-c
    try:
        Thread(target=main_loop, args=()).start()
    except Exception, reason:
        print reason

if __name__ == '__main__':
    sys.exit(main(sys.argv))
Was it helpful?

Solution

You are terminating your main thread with this statement:

if __name__ == '__main__':
    sys.exit(main(sys.argv))

So your signal handler never gets to run. The signal handler is part of the main thread not the main_loop thread you created. So once the main thread exits there's no signal handler function to call anymore.

You need something like this:

def sighandler(signum, frame):
    print 'signal handler called with signal: %s ' % signum
    global shutdown_flag
    shutdown_flag = True
    sys.exit() # make sure you add this so the main thread exits as well.

if __name__ == '__main__':
    main(sys.argv)
    while 1:  # this will force your main thread to live until you terminate it.
       time.sleep(1) 

A simple test to see how many threads are running in your program is this:

def main_loop():
    while not shutdown_flag:
        collect_data() # contains some print "data" statements
        time.sleep(5)
        import threading
        print threading.enumerate()
    print "done (killed)"
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top