Every stop — control-socket stop, dependency shutdown, or gopherd's own
graceful exit — follows the same per-service contract: send stop-signal
(default SIGTERM) to the service's process group, wait kill-delay
(default 10s, matching Docker's stop timeout and well under the 30s
Kubernetes pod grace period), then SIGKILL whatever is still alive.
processes:
- name: graceful
command: /bin/sh
args: ["-c", "trap 'kill $!; exit 0' INT; sleep 300 & wait"]
stop-signal: SIGINT
on-failure: shutdown
- name: stubborn
command: /bin/sh
args: ["-c", "trap '' TERM; while true; do sleep 1 || true; done"]
kill-delay: 2s
on-failure: shutdownstop-signalaccepts names with or without theSIGprefix (SIGINT,INT). Use e.g.SIGQUITfor nginx's graceful shutdown.- The signal goes to the whole process group (each service runs in its own
session), so shell wrappers and their children all receive it. Caveat:
non-interactive shells start background jobs (
cmd &) with SIGINT/SIGQUIT ignored — a wrapper's trap shouldkillthem itself, as above. - The escalation covers the whole group even when the leader exits promptly:
members that survive the stop signal (ignored signal, forked workers) are
SIGKILLed at
kill-delay— the trap pattern above is the graceful path, the escalation is the backstop. kill-delay: 0disables the SIGKILL escalation entirely — the service gets unlimited time to exit, and surviving group members are tolerated.- A stop via the control socket is intentional: the exit does not trigger
on-success/on-failureactions, and gopherd stays up.
gopherd graceful stop— the service traps SIGINT and exits immediately.gopherd stubborn stop— the shell ignores SIGTERM (the group signal kills itssleep, but the loop respawns it); afterkill-delaygopherd SIGKILLs the group and the service reports stopped.
Run level. The test stops graceful and asserts it exits promptly on
SIGINT; then stops stubborn (kill-delay shortened), asserts it is still
alive right after the stop signal, and that it reports stopped only after
the SIGKILL escalation. SIGTERM then yields a clean exit 0.
go test ./documentation/stop-signal/ -v