Graceful Shutdown for HTTP Servers
Demonstrates how to stop an HTTP server cleanly instead of abruptly killing connections.
main.go
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
package main
import (
"context"
"fmt"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
)
// handler provides a simple HTTP endpoint
func handler(w http.ResponseWriter, r *http.Request) {
// Simulate work that takes time to complete
time.Sleep(2 * time.Second)
fmt.Fprintf(w, "Request processed successfully!\n")
}
func main() {
// Create router and register handler
r := http.NewServeMux()
r.HandleFunc("/api/process", handler)
// Configure HTTP server with timeouts (critical for production)
srv := &http.Server{
Addr: ":8080",
Handler: r,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
IdleTimeout: 15 * time.Second,
}
// Start server in a goroutine to avoid blocking
go func() {
log.Printf("Server starting on %s", srv.Addr)
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatalf("Failed to start server: %v", err)
}
}()
// Set up signal handling for graceful shutdown
sigChan := make(chan os.Signal, 1)
// Listen for SIGINT (Ctrl+C) and SIGTERM (system shutdown)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
// Block until a signal is received
sig := <-sigChan
log.Printf("Received signal: %v. Initiating graceful shutdown...", sig)
// Create context with timeout for shutdown (allow time for active requests)
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
// Perform graceful shutdown
if err := srv.Shutdown(ctx); err != nil {
log.Fatalf("Server shutdown failed: %v", err)
}
log.Println("Server shutdown completed successfully")
}How It Works
Demonstrates how to stop an HTTP server cleanly instead of abruptly killing connections.
Creates ServeMux handlers, starts the server in a goroutine, listens for SIGINT or SIGTERM, calls Shutdown with a timeout context to drain ongoing requests, and logs shutdown progress or errors.
Key Concepts
- 1Sets read, write, and idle timeouts to protect from slowloris clients.
- 2Separate goroutine runs ListenAndServe while main waits on signals.
- 3Shutdown uses context to bound the graceful period and cancels outstanding requests.
- 4Error handling differentiates normal http.ErrServerClosed from real failures.
When to Use This Pattern
- Web services that need predictable restarts during deployments.
- Graceful rollouts behind load balancers.
- Local development to show how to stop servers without killing processes.
- Workloads that must flush logs or queues before exit.
Best Practices
- Always use Shutdown instead of Close for HTTP servers in production.
- Tune timeout durations to match expected request lengths.
- Handle multiple signals to allow a second interrupt to force exit if needed.
- Log shutdown steps so operators know when draining finishes.
Go Version1.8
Difficultyintermediate
Production ReadyYes
Lines of Code62