When building a Python script that is long running or has to manage some state on termination it is helpful to handle a couple of signals:
SIGINT: The signal sent when pressing Ctrl+C
SIGQUIT: Meant to terminate the process, sent by
killand process managers like systemd or supervisord
Handling them is possible with Pythons
import signals class SignalHandler: stop = False def __init__(self): # Ctrl+C signal.signal(signal.SIGINT, self.exit_gracefully) # Supervisor/process manager signals signal.signal(signal.SIGTERM, self.exit_gracefully) signal.signal(signal.SIGQUIT, self.exit_gracefully) def exit_gracefully(self, *args): self.stop = True
Example 1: Simple loop
The simplest example is using the
SignalHandler as the condition on the loop
and have code to stop gracefully below the loop.
print("Starting program") signal_handler = SignalHandler() while not signal_handler.stop: do_something() print("Saving state and stopping gracefully")
Example 2: Loop with sleep
Sometimes a long running task sleeps for long amounts of time, which makes it impossible to react to the loop condition.
In this case the simplest solution is to break up the large sleep into shorter sleep intervals
SignalHandler in between sleeping.
import time TOTAL_SLEEP = 60 print("Starting program") signal_handler = SignalHandler() while not signal_handler.stop: do_something() # Instead of time.sleep(TOTAL_SLEEP) for _ in range(0, TOTAL_SLEEP): time.sleep(1) if signal_handler.stop: break print("Saving state and stopping gracefully")
break then brings us out into the
ending the current iteration and forcing a new check on the
therefore ending it and allowing the program to end.