Graceful Shutdown
Gracefully stop HTTP servers, finish active requests, and safely release resources during application shutdown.
Graceful shutdown allows the HTTP server to stop accepting new requests while allowing active requests to finish safely.
This is important for:
- production deployments
- container orchestration
- Kubernetes shutdowns
- zero-downtime restarts
- resource cleanup
- preventing interrupted requests
Without graceful shutdown, terminating the application immediately can interrupt active client requests and leave resources in an inconsistent state.
Basic Graceful Shutdown
The router package supports graceful server shutdown using Go’s standard shutdown mechanisms.
Example:
package main
import (
"context"
"log/slog"
"net/http"
"os"
"os/signal"
"syscall"
"time"
"github.com/netlifeguru/router"
)
func main() {
r := router.New()
r.GET("/", func(w http.ResponseWriter, req *http.Request, ctx *router.Context) {
w.Write([]byte("hello world"))
})
go func() {
if err := r.ListenAndServe(":8000"); err != nil && err != http.ErrServerClosed {
slog.Error("failed to start server", "error", err)
os.Exit(1)
}
}()
slog.Info("server started", "addr", ":8000")
stop := make(chan os.Signal, 1)
signal.Notify(stop,
os.Interrupt,
syscall.SIGTERM,
)
<-stop
slog.Info("shutdown signal received")
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
if err := r.Shutdown(ctx); err != nil {
slog.Error("graceful shutdown failed", "error", err)
os.Exit(1)
}
slog.Info("server stopped gracefully")
}Shutdown Flow
Graceful shutdown follows this lifecycle:
signal received
↓
stop accepting new connections
↓
wait for active requests
↓
close resources
↓
shutdown completeThis prevents requests from being terminated unexpectedly during deployment or restart operations.
Shutdown Timeout
Shutdown should always use a timeout.
Example:
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)This prevents the application from hanging forever if requests never complete.
Typical timeout values:
| Environment | Recommended Timeout |
|---|---|
| Local Development | 5s |
| APIs | 10s |
| Long-running requests | 30s+ |
Kubernetes Compatibility
Graceful shutdown works well with Kubernetes and container orchestration systems.
Typical deployment lifecycle:
SIGTERM
↓
readiness probe fails
↓
traffic stops
↓
active requests complete
↓
container exitsThis helps avoid dropped requests during rolling deployments.
Resource Cleanup
Graceful shutdown is also useful for releasing resources safely.
Examples:
- database connections
- message queues
- background workers
- file handles
- metrics exporters
- external clients
Example:
defer db.Close()
defer logger.Close()Multi-Server Shutdown
When using multi-server mode:
r.MultiListenAndServe(...)the router manages shutdown for all listeners automatically.
This ensures all active HTTP servers stop consistently during application termination.
Logging Shutdown Events
Shutdown events should always be logged.
Example:
slog.Info("shutdown signal received")Example output:
2026-05-12 22:31:10 [INFO] shutdown signal received
2026-05-12 22:31:10 [INFO] server stopped gracefullyThis simplifies operational monitoring and deployment debugging.
Notes
Graceful shutdown only waits for active HTTP requests.
Applications are still responsible for safely stopping:
- background goroutines
- queue consumers
- scheduled jobs
- external connections
- long-running workers
before exiting the process.
Request Lifecycle
Understand how an HTTP request moves through the router, from route matching and middleware execution to handler response and context cleanup.
Project Information
Documentation links, versioning policy, contribution guidelines, licensing, and project resources for the NLG Router package.