Question

I have a piece of Python code as below:

import sys
import signal
import atexit

def release():
    print "Release resources..."

def sigHandler(signo, frame):
    release()
    sys.exit(0)

if __name__ == "__main__":
    signal.signal(signal.SIGTERM, sigHandler)
    atexit.register(release)

    while True:
        pass

The real code is far more complex than this snippets, but the structures are the same: i.e. main function maintains an infinite loop.

I need a signal callback to release the resources occupied, like DB handle. Then I add a SIGTERM handler, in case the server is killed, which simply invoke the release function and then exit the process. The atexit one aims to handling process complete successfully.

Now I have a problem I just want release to be invoked only once when the process is killed. Any improvement on my code?

Was it helpful?

Solution

Well, according to the documentation atexit handlers aren't executed if the program is killed by a signal not handled by Python, or in case of internal error, or if os._exit() is called. So I would use something like this (almost copied your code):

import sys
import signal
import atexit

def release():
    print "Release resources..."

def sigHandler(signo, frame):
    sys.exit(0)

if __name__ == "__main__":
    atexit.register(release)
    signal.signal(signal.SIGTERM, sigHandler)

    while True:
        pass

I've checked release() is called once and only once in case of both TERM (issued externally) and INTR signals (Ctrl-C from keyboard). If you need, you may install more signal handlers (e.g. for HUP etc). If you need "a more graceful shutdown", you should find a way to gracefully break the loop and/or install external "shutdown handlers" (in case of SIGKILL you won't get a chance to cleanly release resources) or simply make your application be ACID.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top