Graceful Shutdown
In production systems, processes do not live forever.
They are stopped and restarted due to:
- Deployments
- Scaling events
- Configuration changes
- Node failures
- Manual operations
A graceful shutdown ensures that ongoing requests are allowed to complete, while new requests are rejected, preventing partial responses and data corruption.
Plumego does not handle shutdown automatically.
This is intentional.
Graceful shutdown is a process-level concern, not a framework feature.
What Happens Without Graceful Shutdown
Without proper shutdown handling:
- In-flight requests are terminated abruptly
- Clients receive connection errors
- Partial writes may occur
- Background operations may be cut off
- Logs become misleading
- Data consistency may be compromised
These failures are intermittent and difficult to reproduce.
Design Principles
A correct graceful shutdown strategy must ensure:
- Stop accepting new requests
- Allow in-flight requests to finish
- Respect timeouts
- Release resources cleanly
- Exit the process predictably
Plumego aligns naturally with Go’s standard shutdown mechanisms.
Using net/http Shutdown Semantics
Plumego runs on top of Go’s net/http.Server.
Go provides built-in support for graceful shutdown via:
server.Shutdown(ctx)
This method:
- Stops accepting new connections
- Waits for active requests to complete
- Honors context cancellation and deadlines
Plumego relies on this mechanism.
Step 1: Control the HTTP Server Explicitly
Instead of calling app.Run() directly, create and manage the server yourself.
Conceptual example:
app := plumego.New()
// register routes and middleware
server := &http.Server{
Addr: ":8080",
Handler: app,
}
This gives you full control over the server lifecycle.
Step 2: Listen for Shutdown Signals
Most production environments send termination signals:
SIGINT(Ctrl+C)SIGTERM(container shutdown)
Set up a signal listener:
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer stop()
This context will be canceled when a shutdown signal is received.
Step 3: Start the Server in a Goroutine
Run the HTTP server asynchronously:
go func() {
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatalf("server error: %v", err)
}
}()
This allows the main goroutine to wait for shutdown signals.
Step 4: Initiate Graceful Shutdown
When the shutdown signal arrives:
<-ctx.Done()
shutdownCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
if err := server.Shutdown(shutdownCtx); err != nil {
log.Printf("graceful shutdown failed: %v", err)
}
Key points:
- Use a timeout to avoid hanging indefinitely
- Log shutdown failures
- Allow in-flight requests to complete within the timeout
Step 5: Clean Up Resources
After the server shuts down:
- Close database connections
- Flush logs
- Stop background workers
- Release external resources
This cleanup should respect the same shutdown context where possible.
Interaction with Middleware
Middleware should be written with shutdown in mind:
- Long-running operations should respect
ctx.Done() - Background goroutines should be cancellable
- Blocking operations should have timeouts
Because Plumego embeds context.Context, cancellation propagates naturally.
Handling Long-Lived Connections
Certain features complicate graceful shutdown:
- WebSocket connections
- Streaming responses
- Long polling
Strategies include:
- Closing connections explicitly
- Sending shutdown notifications to clients
- Enforcing connection timeouts
These require explicit handling, not framework magic.
Graceful Shutdown in Containers
In containerized environments (Docker, Kubernetes):
- Ensure
SIGTERMis handled - Configure termination grace periods
- Align shutdown timeout with platform settings
Mismatch between application and platform timeouts leads to forced termination.
Common Mistakes
Calling os.Exit Directly
This bypasses deferred cleanup and prevents graceful shutdown.
Avoid it.
Ignoring Context Cancellation
Long-running operations that ignore cancellation will delay or block shutdown.
Infinite Shutdown Timeouts
Always set an upper bound.
A stuck shutdown is worse than a forced one.
Testing Graceful Shutdown
You should test shutdown behavior by:
- Sending requests
- Triggering shutdown signals
- Verifying responses complete
- Ensuring no new requests are accepted
This catches issues that unit tests cannot.
Summary
In Plumego:
- Graceful shutdown is explicit
- Built on Go’s standard HTTP server
- Integrated via context cancellation
- Essential for production reliability
Graceful shutdown is not an optimization.
It is a correctness requirement.
Next
With graceful shutdown implemented, you are ready to handle external interactions safely.
Next guide:
→ Webhook Server
This explains how to receive and validate external callbacks reliably.