Free — no signup required

Signal Handling: Graceful Shutdowns

2 min read

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.

This is one of 18 chapters

Every chapter is free — Kubernetes, Terraform, SRE, distributed systems, and more — with fast daily review built in.

Sign up free