Go cookbook · Beginner

Shut down an HTTP server gracefully

Deploys kill the process mid-request, dropping connections and losing work.

Create a free account to save this page, take notes and track your progress. Sign in

Approach

Listen for SIGINT/SIGTERM with signal.NotifyContext, stop accepting new connections with Server.Shutdown(ctx) and give in-flight requests a deadline. Close other resources afterwards.

Solution

package main

import (
	"context"
	"errors"
	"log/slog"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"
)

func main() {
	ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
	defer stop()

	mux := http.NewServeMux()
	mux.HandleFunc("GET /slow", func(w http.ResponseWriter, r *http.Request) {
		time.Sleep(3 * time.Second)
		w.Write([]byte("done\n"))
	})
	srv := &http.Server{Addr: ":8080", Handler: mux, ReadHeaderTimeout: 5 * time.Second}

	go func() {
		if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
			slog.Error("server failed", "err", err)
			os.Exit(1)
		}
	}()
	slog.Info("listening", "addr", srv.Addr)

	<-ctx.Done() // wait for a signal
	slog.Info("shutting down")
	shutdownCtx, cancel := context.WithTimeout(context.Background(), 25*time.Second)
	defer cancel()
	if err := srv.Shutdown(shutdownCtx); err != nil {
		slog.Error("forced shutdown", "err", err)
	}
	// close database pools, flush telemetry, stop workers here
	slog.Info("stopped")
}

Pitfalls

  • A shutdown timeout longer than the orchestrator's grace period (Kubernetes default 30 s).
  • Treating http.ErrServerClosed from ListenAndServe as a failure.
  • Long-lived connections (WebSockets, streaming) aren't tracked by Shutdown; signal them via RegisterOnShutdown.

Variations

  • Fail the readiness probe first, wait a few seconds for load balancers to notice, then shut down.
  • Pass ctx to background workers so they stop on the same signal.

Further reading: Server.Shutdown

Reference: https://pkg.go.dev/net/http#Server.Shutdown

More Go recipes

Was this page helpful?