Graceful shutdown
Without graceful shutdown wired, your server dies immediately on SIGTERM and in-flight requests are dropped. Every production deployment needs this. Ingenium ships gracefulShutdown(server, opts) to handle the lifecycle correctly.
Usage
import { ingenium, gracefulShutdown } from 'ingenium'
const app = ingenium()
const server = await app.listen(3000)
gracefulShutdown(server, {
gracefulTimeoutMs: 10_000, // force-close idle keep-alives after 10s
signals: ['SIGTERM', 'SIGINT'],
onShutdown: async () => {
await db.close()
await queue.flush()
},
})
Behavior
- Listens for the configured signals (default:
SIGTERM,SIGINT). - Stops accepting new connections.
- Lets in-flight requests finish.
- Force-closes idle keep-alive connections after
gracefulTimeoutMs. - Runs
onShutdownfor your cleanup work (DB pools, queues, file handles). - A second signal during shutdown triggers an immediate
exit(1)- the force-quit escape hatch when something is hung.
Why this matters
Container orchestrators (Kubernetes, ECS, Nomad) send SIGTERM before SIGKILL precisely so apps can drain. Without graceful shutdown, every deploy and every pod restart drops every in-flight request that was unlucky enough to be mid-flight. With it, drains are invisible to clients.
Wiring with the close API
server.close({ gracefulTimeoutMs }) is the lower-level primitive gracefulShutdown uses internally. If you want to drive shutdown from your own signal handlers or admin endpoint, call server.close(...) directly.
Where to next?
- Production hardening -
gracefulShutdownis part of the recommended wiring. - Transports - how the underlying server is created.
- Core concepts - the App lifecycle and
server.close(). - WebSocket - additional considerations for long-lived sockets.