Skip to content

go.missing_graceful_shutdown

Stability High

Detects HTTP servers that don’t handle SIGTERM for graceful shutdown, causing dropped requests during deployments.

Without graceful shutdown:

  • Dropped requests — In-flight requests are terminated mid-processing
  • Data loss — Partial writes, uncommitted transactions
  • Connection errors — Clients receive connection reset errors
  • Deployment failures — Rolling updates cause user-visible errors
// ❌ Before (no graceful shutdown)
func main() {
http.ListenAndServe(":8080", handler)
}
// ✅ After (graceful shutdown)
func main() {
server := &http.Server{
Addr: ":8080",
Handler: handler,
}
// Start server in goroutine
go func() {
if err := server.ListenAndServe(); err != http.ErrServerClosed {
log.Fatal(err)
}
}()
// Wait for interrupt signal
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
// Graceful shutdown with timeout
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
if err := server.Shutdown(ctx); err != nil {
log.Fatal("Server forced to shutdown:", err)
}
log.Println("Server exited gracefully")
}
  • http.ListenAndServe() without signal handling
  • Missing server.Shutdown() calls
  • log.Fatal() in signal handlers (prevents cleanup)
  • Hardcoded exits without cleanup

Unfault generates patches that add signal handling and graceful shutdown:

import (
"context"
"os"
"os/signal"
"syscall"
)
// Graceful shutdown setup
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
spec:
terminationGracePeriodSeconds: 30
containers:
- name: app
lifecycle:
preStop:
exec:
command: ["/bin/sh", "-c", "sleep 5"]