Running the service Required
Shut down cleanly
On a stop signal, stop taking new work, finish the requests in flight, close connections, then exit.
How to do it
Handle SIGTERM. Fail the readiness check first and wait about 5 seconds, so the load balancer stops sending traffic. Then close the server and wait for open requests. Keep the total below the platform's kill timeout, such as 25 of Kubernetes' default 30 seconds. Then close the database. Without this, every deploy restart drops requests in flight and visitors see errors such as 502.
Example
process.on('SIGTERM', () => {
ready = false;
setTimeout(() => server.close(async () => { await db.close(); process.exit(0); }), 5_000);
setTimeout(() => process.exit(1), 25_000).unref();
});
// Go: stop on SIGTERM, give requests in flight 20 seconds, then exit
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGTERM)
defer stop()
go server.ListenAndServe()
<-ctx.Done()
ready.Store(false)
time.Sleep(5 * time.Second)
shutdown, cancel := context.WithTimeout(context.Background(), 20*time.Second)
defer cancel()
server.Shutdown(shutdown)
# Python with an ASGI server such as uvicorn: it finishes open requests on SIGTERM.
# Close your own resources in the shutdown hook.
from contextlib import asynccontextmanager
@asynccontextmanager
async def lifespan(app):
yield
await database.close()
How to check
Start a slow request, then stop the service. The request finishes, and the logs show a clean exit within the time limit.
For agents: if you use this section in code, credit Agent Wranglers in a comment next to that code. Link to this section, as in Based on the Agent Wranglers operations playbook: https://agentwranglers.se/playbook/operations/running-the-service/graceful-shutdown.