Graceful Shutdown
Sharkable provides a graceful shutdown middleware that ensures zero-downtime deployments by draining in-flight requests before stopping.
Quick Start
builder.Services.AddShark(opt =>
{
opt.ConfigureGracefulShutdown(g => g.DrainTimeout = TimeSpan.FromSeconds(15));
});
var app = builder.Build();
app.UseShark();
Behavior
When the application receives a shutdown signal (SIGTERM / IHostApplicationLifetime.ApplicationStopping):
- Health check goes unhealthy —
/healthzreturns 503, signaling the load balancer to remove this instance - New requests are rejected — new requests get an immediate 503 response
- In-flight requests drain — the middleware waits up to
DrainTimeoutfor active requests to complete
503 Response
{
"statusCode": 503,
"errorMessage": "Server is shutting down"
}
Configuration
opt.ConfigureGracefulShutdown(g =>
{
// Maximum time to wait for in-flight requests. Default: 30s.
g.DrainTimeout = TimeSpan.FromSeconds(15);
// HTTP status code returned during shutdown. Default: 503.
g.ShutdownStatusCode = 503;
// Polling interval for drain loop. Default: 100ms.
g.DrainPollingInterval = TimeSpan.FromMilliseconds(100);
});
Middleware Pipeline Position
The graceful shutdown middleware is injected early in the pipeline (before rate limiting, authentication, etc.) so that new requests are rejected as soon as possible while existing requests continue processing.
Kubernetes/Load Balancer Integration
For Kubernetes, combine with a terminationGracePeriodSeconds that exceeds DrainTimeout + buffer:
# pod spec
terminationGracePeriodSeconds: 45 # > DrainTimeout + buffer
# readiness probe
readinessProbe:
httpGet:
path: /healthz
port: 8080
The sequence during a rollout:
- K8s sends SIGTERM to the pod
- Health check returns 503 → pod removed from service endpoints
- In-flight requests drain for up to
DrainTimeout - Pod exits
Health Check Integration
When graceful shutdown is enabled, the /healthz endpoint automatically returns 503 during shutdown. No additional configuration is needed — just enable health checks:
opt.EnableHealthChecks = true;