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.go

Expected output:

running, pid 4812
SIGHUP: reloading config (no restart)
shutdown signal: draining and exiting

The 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.

💻 Run locally

Copy the code above and run it on your machine

© 2026 ByteLearn.dev. Free courses for developers. · Privacy