Catching Ctrl+C and Other Signals
When a user presses Ctrl+C, the operating system sends a SIGINT (Signal Interrupt) to your process. When a system wants to shut down your process cleanly, it sends SIGTERM (Signal Terminate). When it wants to force-kill it, it sends SIGKILL (which cannot be caught).
By default, Python raises a KeyboardInterrupt exception on SIGINT, which — if uncaught — prints a messy stack trace to the screen and exits. This looks unprofessional and, more importantly, may leave your tool in a bad state: a half-written file, a dangling lock file, a temporary directory that never gets cleaned up, or a remote operation left in an unknown state.
Robust Signal Handling:
Register a handler that catches the signal, performs cleanup, and exits cleanly:
import signal
import sys
import os
# Track resources that need cleanup
lock_file = "/tmp/mytool.lock"
def cleanup():
"""Remove any resources created during the run."""
if os.path.exists(lock_file):
os.remove(lock_file)
print("\nLock file removed.", file=sys.stderr)
def signal_handler(sig, frame):
print("\nOperation cancelled. Cleaning up...", file=sys.stderr)
cleanup()
sys.exit(130) # 128 + SIGINT(2) — the conventional exit code for Ctrl+C
# Register handlers
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
# Create the lock file
open(lock_file, "w").close()
# ... do work ...
Note the exit code: 130 is the conventional exit code for a process terminated by Ctrl+C (128 + 2, where 2 is the signal number for SIGINT). Using 130 instead of 1 lets callers distinguish between "the tool failed" and "the user cancelled it" — a distinction that matters for retry logic in automation.
The SIGTERM Case:
In containerized environments (Docker, Kubernetes), when a container is stopped, the runtime sends SIGTERM to the main process and gives it a grace period (typically 30 seconds) to shut down cleanly before sending SIGKILL. If your tool doesn't handle SIGTERM, it gets killed mid-operation every time a container is restarted. Handling SIGTERM with the same cleanup logic as SIGINT is essential for tools that run inside containers.