Programming

Graceful Shutdown Node.js: Drain Requests Before Closing Resources

tuyenpham
October 12, 2026 schedule 5 min read
graceful shutdown Node.js: process overview

A graceful shutdown Node.js workflow gives in-flight work a bounded opportunity to finish before a process exits. It matters during deployments, autoscaling, and planned restarts, when an otherwise healthy service is removed from traffic. Catching a signal alone is not a complete shutdown design. The application must stop taking work, preserve the dependencies active work still needs, and exit within the platform deadline. Begin with a small HTTP service, then account for its database pool, workers, subscriptions, and long-lived connections.

graceful shutdown Node.js: a practical implementation workflow

Coordinate readiness with traffic removal

When termination begins, mark the instance unready so the routing platform can stop choosing it. That change is not instant proof that no new request can arrive; load balancers, proxies, and existing connections have their own behavior. Decide how requests received during draining are handled. Coordinate the application deadline with the orchestrator grace period and any pre-stop hook. A liveness probe serves a different purpose from readiness. Document the actual platform sequence instead of assuming that one signal creates a perfectly isolated shutdown boundary.

graceful shutdown Node.js: overview
Overview

Drain HTTP requests before closing dependencies

On modern Node.js releases, server.close stops accepting new connections and closes idle HTTP connections while active requests are allowed to complete. The callback indicates that server closure has finished. Keep the database pool and other resources available until the requests that use them have drained. Closing the pool first can turn an otherwise successful request into a failure. Existing upgraded sockets, such as WebSockets, need separate handling. Review the Node.js version-specific behavior and the framework lifecycle hooks before applying a generic shutdown helper.

Use a bounded deadline and an escalation path

A slow or stuck request must not keep the process alive indefinitely. Start a shutdown timer that fits within the platform termination allowance. When the deadline expires, report that draining was incomplete and use the documented forced-close strategy. Forced HTTP connection closure can interrupt active clients and does not close every upgraded protocol connection. A process exit is therefore an escalation, not proof of successful cleanup. Track the difference between a clean drain, cleanup failure, and deadline expiry in metrics or logs so release reliability can be evaluated honestly.

Make shutdown handling idempotent

graceful shutdown Node.js: checklist
Checklist

Both an operator and the platform may send signals, and multiple cleanup triggers can race. Use a state flag or a single shared shutdown promise so resource closure starts once. Installing a signal handler changes default process behavior on relevant platforms, so ensure the handler actually reaches completion or an escalation. Do not place awaited work in the synchronous exit event and expect it to finish. Keep error handling explicit, including cleanup errors, and avoid printing secret-bearing state while reporting a termination failure.

Include workers and durable jobs

Stop queue consumers from taking new jobs, then allow active jobs to finish or return them through the queue visibility and retry contract. A job acknowledged before its effect is durable can be lost during termination. A retried job may repeat effects, so consumers need appropriate idempotency. Close telemetry and other resources according to their documented flush behavior, with bounded waits. The minimal code only covers an HTTP demonstration. Production services must inventory everything that keeps the process alive and test the interaction between each resource and the shutdown order.

Code example

graceful shutdown Node.js: workflow
Workflow

Run this as an .mjs file on a supported modern Node.js release. This local HTTP-only demonstration deliberately omits database pools, readiness routing, and upgraded sockets. In a real service, close remaining resources after request draining and before clearing the final cleanup deadline.

import http from "node:http";

let draining = false;
const server = http.createServer((req, res) => {
  res.writeHead(draining ? 503 : 200);
  res.end(draining ? "draining" : "ok");
});
server.listen(3000, "127.0.0.1");

function shutdown() {
  if (draining) return;
  draining = true;
  const deadline = setTimeout(() => process.exit(1), 10000);
  server.close((error) => {
    clearTimeout(deadline);
    process.exitCode = error ? 1 : 0;
  });
}
process.on("SIGTERM", shutdown);
process.on("SIGINT", shutdown);

Worked example

A hypothetical API closes its database pool immediately after SIGTERM, causing active requests to fail. The team changes the sequence: mark unready, stop accepting work, drain HTTP, then close the pool within a shared deadline. A separate worker stops polling and finishes or releases its job under the queue contract. Tests include a slow request and repeated termination signals. The deployment report distinguishes successful drains from forced exits, so an apparently successful rollout does not conceal interrupted customer operations.

Verification checklist

  • Keep dependencies available until active work drains.
  • Bound the entire shutdown within platform limits.
  • Handle repeat signals without duplicate cleanup.
  • Account separately for jobs and upgraded sockets.
graceful shutdown Node.js: mistakes
Mistakes

Practice task

Add a deliberately slow route to a disposable local server, begin a request, and send SIGTERM while it is active. Verify that the request finishes within your chosen deadline. Repeat with a route that exceeds the deadline and record the forced outcome. Add a fake database resource and assert that it closes after request completion. Send the signal twice and confirm cleanup runs once. Finally, compare the experiment with the actual deployment platform grace period and traffic-removal sequence.

Sources and related reading

Consult Node.js HTTP server close methods; Node.js process signals; Kubernetes pod termination for API contracts and implementation details. Continue with Deployment Checklist and Ci Cd Pipeline for related concepts.

Share Article: share

Discussion

Join the conversation

Leave a Reply

Your email address will not be published. Required fields are marked *

Related Articles