I have a script that instantiates a number of objects from other classes. When the calling script ends, these objects need to do some cleanup work, especially the closing and deleting of some tempfiles.
I've experimented with a number of ways to trigger the cleanup, and a number of them work when the calling script ends nicely...but none of them work in the event the calling script crashes or ends unexpectedly (like due to an uncaught error).
Is it possible to get the "child objects" (if that's the right term) to run their cleanup in the case of a crash or unexpected error?
Here's some test scripts...
THE OBJECT CLASS WHICH GETS CALLED...
import signal
import atexit
import os
class testme(object):
def __init__(self):
self.var = 1
self.sigs()
atexit.register(self.close)
def __enter__(self):
print "Hit enter"
def sigs(self):
for i in [x for x in dir(signal) if x.startswith("SIG")]:
try:
print "setting signal ", str(i)
signum = getattr(signal,i)
signal.signal(signum,self.close)
except Exception, e:
print ("Skipping " + str(i) + " in set_signal_handler")
def __del__(self):
print "Hit del"
self.close()
def __exit__(self, exception_type, exception_value, traceback):
print "Hit exit"
self.close()
def close(self):
print "Closing"
# Perform cleanup actions here
# Especially closing and deleting temp files
(The different signals that the "sigs()" function is [hopefully] setting is at the end of this post)
test2.py
import time
import testme
import sys
if __name__ == "__main__":
with testme.testme() as obj:
time.sleep(30)
sys.exit()
test3.py
import time
import testme
import sys
if __name__ == "__main__":
obj = testme.testme()
time.sleep(30)
sys.exit()
If I run test2.py and let it finish normally I get the following...
setting signal SIGABRT
setting signal SIGALRM
[...snip...]
Skipping SIG_DFL in set_signal_handler
setting signal SIG_IGN
Hit enter
Hit exit
Closing
Closing
Hit del
Closing
If I run test2.py and use "kill -9" to end it (crash) I get...
setting signal SIGABRT
[...snip...]
setting signal SIG_IGN
Hit enter
If I run test3.py and let it finish, I get...
setting signal SIGABRT
[...snip...]
setting signal SIG_IGN
Closing
Hit del
Closing
If I run test3.py and use "kill -9" on it, I get the following...
setting signal SIGABRT
[...snip...]
setting signal SIG_IGN
(in other words...nothing)
EDIT: I did find that uncaught exceptions in the calling script do allow the del() in the child objects to run. Still wondering if there's a way to cleanly close out the child objects on other failures.
SIGNALS THAT (I hope) ARE GETTING SET BY sigs()...
setting signal SIGABRT
setting signal SIGALRM
setting signal SIGBUS
setting signal SIGCHLD
setting signal SIGCLD
setting signal SIGCONT
setting signal SIGFPE
setting signal SIGHUP
setting signal SIGILL
setting signal SIGINT
setting signal SIGIO
setting signal SIGIOT
setting signal SIGKILL
Skipping SIGKILL in set_signal_handler
setting signal SIGPIPE
setting signal SIGPOLL
setting signal SIGPROF
setting signal SIGPWR
setting signal SIGQUIT
setting signal SIGRTMAX
setting signal SIGRTMIN
setting signal SIGSEGV
setting signal SIGSTOP
Skipping SIGSTOP in set_signal_handler
setting signal SIGSYS
setting signal SIGTERM
setting signal SIGTRAP
setting signal SIGTSTP
setting signal SIGTTIN
setting signal SIGTTOU
setting signal SIGURG
setting signal SIGUSR1
setting signal SIGUSR2
setting signal SIGVTALRM
setting signal SIGWINCH
setting signal SIGXCPU
setting signal SIGXFSZ
setting signal SIG_DFL
Skipping SIG_DFL in set_signal_handler
setting signal SIG_IGN
Well your issue is that kill -9
, aka SIGKILL, by its design cannot be caught. It is a guaranteed violent death for the offending process.
The command kill sends the specified signal to the specified process or process group. If no signal is specified, the TERM signal is sent. The TERM signal will kill processes which do not catch this signal. For other processes, it may be necessary to use the KILL (9) signal, since this signal cannot be caught.
For atexit
to work properly, it needs to be able to catch some signal. You can instead try sending kill -15
(SIGTERM).