Signals¶
What is it: Asynchronous notifications from the kernel or another process. The process installs a handler, ignores, or accepts the default action.
Why: primary mechanism for control events: shutdown, interrupt, child exit, error notification.
Common signals:
- SIGINT (2): Ctrl+C. Intercept for graceful shutdown.
- SIGTERM (15): standard shutdown request. kill $PID. Catchable — use for graceful drain.
- SIGKILL (9): immediate, uncatchable, unkillable. Use only when SIGTERM is ignored. No cleanup.
- SIGSEGV (11): segmentation fault. Default: core dump + terminate.
- SIGCHLD (17): child exited. Parent calls waitpid() to reap zombie.
- SIGPIPE (13): write to closed socket/pipe. Default: terminate. Servers ignore it; handle EPIPE from write() instead.
- SIGUSR1/2 (10/12): user-defined. Log rotation, config reload without restart.
Graceful shutdown in Go:
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, syscall.SIGTERM, syscall.SIGINT)
<-sigCh
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
server.Shutdown(ctx) // stop accepting, drain in-flight requests
Kubernetes: SIGTERM → wait terminationGracePeriodSeconds (default 30s) → SIGKILL.
Signal → context cancellation pattern:
Convert OS signal to context cancellation at the top of main(). All components receive a root context. On SIGTERM, cancel the root context. All goroutines selecting on ctx.Done() begin cleanup concurrently within the grace period.
Real-world usage: Proxel workers catch SIGTERM, stop pulling from Redis Stream, allow in-flight jobs to finish within 30s, then exit. Jobs not ACKed within the XCLAIM timeout (60s) are automatically requeued by the monitor process.
Common pitfall¶
Not handling SIGTERM at all (leaving the default action, which is
immediate termination) means every deploy or scale-down kills in-flight
requests mid-processing — no different from SIGKILL in effect, even
though the orchestrator gave a grace period specifically to avoid
this. The grace period is wasted if nothing in the application
actually listens for the signal and uses that window to drain; adding
the handler is what turns an available grace period into an actual
zero-downtime deploy.