Enter the signal_name with uppercase characters. For example, if you want to send the SIGTERM signal, you would enter kill -TERM pid not kill -SIGTERM pid. When using the tcsh kill command, do not use the first three characters (SIG) of the signal_name. There is no default job.
If a process does not respond to any other termination signals, sending it a SIGKILL signal will almost always cause it to go away. In fact, if SIGKILL fails to terminate a process, that by itself constitutes an operating system bug which you should report.
Description. kill ends a process by sending it a signal. The default signal is SIGTERM.
SIGTERM (15) The default behavior of kill is to send the SIGTERM signal to a process, by which we ask that process to gracefully shutdown.
A class based clean to use solution:
import signal
import time
class GracefulKiller:
kill_now = False
def __init__(self):
signal.signal(signal.SIGINT, self.exit_gracefully)
signal.signal(signal.SIGTERM, self.exit_gracefully)
def exit_gracefully(self, *args):
self.kill_now = True
if __name__ == '__main__':
killer = GracefulKiller()
while not killer.kill_now:
time.sleep(1)
print("doing something in a loop ...")
print("End of the program. I was killed gracefully :)")
First, I'm not certain that you need a second thread to set the shutdown_flag
.
Why not set it directly in the SIGTERM handler?
An alternative is to raise an exception from the SIGTERM
handler, which will be propagated up the stack. Assuming you've got proper exception handling (e.g. with with
/contextmanager
and try: ... finally:
blocks) this should be a fairly graceful shutdown, similar to if you were to Ctrl+C your program.
Example program signals-test.py
:
#!/usr/bin/python
from time import sleep
import signal
import sys
def sigterm_handler(_signo, _stack_frame):
# Raises SystemExit(0):
sys.exit(0)
if sys.argv[1] == "handle_signal":
signal.signal(signal.SIGTERM, sigterm_handler)
try:
print "Hello"
i = 0
while True:
i += 1
print "Iteration #%i" % i
sleep(1)
finally:
print "Goodbye"
Now see the Ctrl+C behaviour:
$ ./signals-test.py default
Hello
Iteration #1
Iteration #2
Iteration #3
Iteration #4
^CGoodbye
Traceback (most recent call last):
File "./signals-test.py", line 21, in <module>
sleep(1)
KeyboardInterrupt
$ echo $?
1
This time I send it SIGTERM
after 4 iterations with kill $(ps aux | grep signals-test | awk '/python/ {print $2}')
:
$ ./signals-test.py default
Hello
Iteration #1
Iteration #2
Iteration #3
Iteration #4
Terminated
$ echo $?
143
This time I enable my custom SIGTERM
handler and send it SIGTERM
:
$ ./signals-test.py handle_signal
Hello
Iteration #1
Iteration #2
Iteration #3
Iteration #4
Goodbye
$ echo $?
0
Here is a simple example without threads or classes.
import signal
run = True
def handler_stop_signals(signum, frame):
global run
run = False
signal.signal(signal.SIGINT, handler_stop_signals)
signal.signal(signal.SIGTERM, handler_stop_signals)
while run:
pass # do stuff including other IO stuff
I think you are near to a possible solution.
Execute mainloop
in a separate thread and extend it with the property shutdown_flag
. The signal can be caught with signal.signal(signal.SIGTERM, handler)
in the main thread (not in a separate thread). The signal handler should set shutdown_flag
to True and wait for the thread to end with thread.join()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With