A
Alexander Staubo
Python does not seem to clean up gracefully on SIGTERM: The exit
sequence is not invoked on termination, so the atexit module cannot be
used to install shutdown logic.
Further, while the signal module allows trapping the signal, it does
not offer a truly portable way of respecting the termination request.
As far as I can see, this issue has been a topic of conversation for
years, but I don't see that it has ever been solved:
http://www.python.org/search/hypermail/python-1992/0206.html
This is what I came up with initially:
previousHandler = None
def handler(signum, frame):
if previousHandler:
previousHandler(signum, frame)
else:
os._exit(128 + signal.SIGTERM)
previousHandler = signal.signal(signal.SIGTERM, handler)
This at least 1) preserves the Python exit sequence, 2) follows Unix
conventions, and 3) is friendly to libraries or anyone else who have
installed their own signal handlers.
I am, however, concerned with the fact that it could be, as Guido
points out, distruptive to things going on concurrently in the
interpreter.
The other, seemingly more elegant solution is to invent your own
exception and add a global exception hook:
class Dummy(Exception): pass
previousHandler = None
def handler(signum, frame):
if previousHandler:
previousHandler(signum, frame)
else:
raise Dummy()
previousHandler = signal.signal(signal.SIGTERM, handler)
def hook(type, value, traceback, previous = sys.excepthook):
if not isinstance(value, Dummy):
previous(type, value, traceback)
This technique has the downside of possibly being caught by alien
code. For example, a signal occuring during the following code
snippet's execution will effectively be ignored:
try:
# ... something ...
except:
logger.error("Something went wrong", exc_info = True)
Would someone please come along with an incredibly elegant hack that
everyone but I knows about?
Alexander.
sequence is not invoked on termination, so the atexit module cannot be
used to install shutdown logic.
Further, while the signal module allows trapping the signal, it does
not offer a truly portable way of respecting the termination request.
As far as I can see, this issue has been a topic of conversation for
years, but I don't see that it has ever been solved:
http://www.python.org/search/hypermail/python-1992/0206.html
This is what I came up with initially:
previousHandler = None
def handler(signum, frame):
if previousHandler:
previousHandler(signum, frame)
else:
os._exit(128 + signal.SIGTERM)
previousHandler = signal.signal(signal.SIGTERM, handler)
This at least 1) preserves the Python exit sequence, 2) follows Unix
conventions, and 3) is friendly to libraries or anyone else who have
installed their own signal handlers.
I am, however, concerned with the fact that it could be, as Guido
points out, distruptive to things going on concurrently in the
interpreter.
The other, seemingly more elegant solution is to invent your own
exception and add a global exception hook:
class Dummy(Exception): pass
previousHandler = None
def handler(signum, frame):
if previousHandler:
previousHandler(signum, frame)
else:
raise Dummy()
previousHandler = signal.signal(signal.SIGTERM, handler)
def hook(type, value, traceback, previous = sys.excepthook):
if not isinstance(value, Dummy):
previous(type, value, traceback)
This technique has the downside of possibly being caught by alien
code. For example, a signal occuring during the following code
snippet's execution will effectively be ignored:
try:
# ... something ...
except:
logger.error("Something went wrong", exc_info = True)
Would someone please come along with an incredibly elegant hack that
everyone but I knows about?
Alexander.