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.

sequenceDiagram participant K8s as Kubernetes participant App K8s->>App: SIGTERM Note over App: stop accepting new requests,<br/>drain in-flight ones App->>App: server.Shutdown(ctx) with 30s timeout alt drained in time App->>K8s: process exits cleanly else grace period expires K8s->>App: SIGKILL (no cleanup possible) end

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.