Graceful Shutdown and SIGHUP Reload
signal.NotifyContext turns SIGINT/SIGTERM into a cancelled context, while SIGHUP on its own channel triggers a config reload without restarting. The demo sends itself both signals so it finishes on its own.
package main
import (
"context"
"fmt"
"os"
"os/signal"
"syscall"
"time"
)
func main() {
// SIGINT/SIGTERM cancel this context for a graceful shutdown.
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
defer stop()
// SIGHUP arrives on its own channel and means "reload".
hup := make(chan os.Signal, 1)
signal.Notify(hup, syscall.SIGHUP)
fmt.Println("running, pid", os.Getpid())
// Demo driver: signal ourselves so the example terminates unattended.
go func() {
time.Sleep(200 * time.Millisecond)
syscall.Kill(os.Getpid(), syscall.SIGHUP)
time.Sleep(200 * time.Millisecond)
syscall.Kill(os.Getpid(), syscall.SIGTERM)
}()
for {
select {
case <-hup:
fmt.Println("SIGHUP: reloading config (no restart)")
case <-ctx.Done():
fmt.Println("shutdown signal: draining and exiting")
return
}
}
}Save the code as main.go and run it:
go run main.goExpected output:
running, pid 4812
SIGHUP: reloading config (no restart)
shutdown signal: draining and exitingThe pid varies, and the program exits on its own after about half a second. To drive it by hand instead, delete the demo goroutine and send signals from another terminal: kill -HUP <pid> to reload, kill -TERM <pid> or Ctrl+C to stop.