# FAQ

> Node.js graceful shutdown FAQ: SIGTERM, server.close(), in-flight requests, frameworks, Docker and Kubernetes, and what shutdown-check does and does not test.

Source: https://shutdown.jscrate.dev/docs/faq
Last updated: 2026-09-23

These answers cover the most common Node.js graceful shutdown questions. Each
answer links to a guide or reference page when you need working code or deeper
troubleshooting.

## What is graceful shutdown in Node.js?

Graceful shutdown is the process of stopping a service without cutting off
work that already started. After `SIGTERM`, the service stops taking new work,
finishes active requests, closes shared resources, and exits before the
platform deadline.

Node.js does not build this application-specific sequence for you. Add a
signal handler or use a shutdown library, then verify the behavior. The
[Node.js guide](https://shutdown.jscrate.dev/docs/guides/graceful-shutdown-nodejs) includes complete
node:http, Express, and Fastify examples.

## Does shutdown-check make my app shut down gracefully?

No. shutdown-check is a test tool, not a shutdown-handler library. It does not
change your service or run inside it.

The tool starts the configured command, opens a real request, sends `SIGTERM`,
and checks the response and process. You still need to implement the handler,
close resources, and choose a drain strategy.

## Why does Node.js exit immediately on SIGTERM?

Without an effective listener, the signal uses its default termination
behavior. Any open HTTP connection can be cut off.

Install a listener on the process that actually runs the server:

```js
process.on("SIGTERM", () => {
  server.close((error) => {
    if (error) process.exitCode = 1;
  });
});
```

If a shell or package-manager wrapper starts Node.js, the signal may stop at
the wrapper. Prefer a direct command such as `node dist/server.js`.

## Why does server.close() not finish?

`server.close()` waits for active connections. It can appear stuck when:

- an HTTP response never ends;
- an upstream or database operation hangs;
- a client keeps a connection active;
- the application closes a dependency that the request still needs;
- another resource keeps Node.js alive after the server closes.

Log the callback, active handlers, and every cleanup step. Add timeouts to
external operations. [SC200](https://shutdown.jscrate.dev/docs/codes/sc200) covers a request that stays
open; [SC300](https://shutdown.jscrate.dev/docs/codes/sc300) covers a process that stays alive after
requests finish.

## Why does my test say the work was never in flight?

The workload ended before the signal, or its start barrier never passed. A
shutdown test cannot prove draining when no work is active.

With `response-headers`, flush headers and keep the body open. With `probe`,
make a separate route change from inactive to active while the operation runs.
See [in-flight work and start barriers](https://shutdown.jscrate.dev/docs/in-flight-work).

## Does it work with Express, Fastify or NestJS?

Yes. shutdown-check does not depend on a framework. It starts a command and
uses local HTTP.

- Express uses the Node.js server returned by `app.listen()`.
- Fastify can close through `fastify.close()`.
- NestJS needs its shutdown hooks configured and awaited.

The service must expose readiness and workload routes and respond to
`SIGTERM`. Framework-specific implementation is covered in the
[graceful shutdown guide](https://shutdown.jscrate.dev/docs/guides/graceful-shutdown-nodejs).

## Does it test databases, queues or WebSockets?

Not directly. shutdown-check observes the service process and HTTP/1
responses. It cannot see internal database or queue state, and it does not
open WebSocket or HTTP/2 sessions.

Use `bodyIncludes` when the response can prove that important work completed.
Add application-specific tests for database transactions, queue
acknowledgement, background tasks, WebSockets, and work that continues after
the response.

## Does it work on Windows?

Not natively. The tool requires POSIX signals and process groups, so it
supports macOS and Linux.

On a Windows workstation, run it in WSL, a Linux container, or Linux CI. The
service and test must run in the same supported environment with access to the
local port.

## Can I run it in Docker or Kubernetes?

Yes, with limits. It can run inside a Linux container that has Node.js 22 or
later. It tests the service process and local HTTP behavior inside that
container.

It does not simulate Kubernetes endpoint removal, `preStop`, sidecars, ingress,
or the cluster grace period. Use the
[Kubernetes guide](https://shutdown.jscrate.dev/docs/guides/kubernetes) to map those settings and test the
remaining behavior in staging.

## How is it different from a shutdown library like terminus?

A library such as terminus implements shutdown behavior inside the service.
shutdown-check tests the behavior from outside the service.

You can use both: a library to register handlers and close resources, then
shutdown-check to prove the real start command, signal path, active request,
exit, and port work together. See the
[comparison page](https://shutdown.jscrate.dev/docs/comparison) for unit tests, scripts, and staging tests
as well.

## Does shutdown-check send SIGINT?

No. Version 1.0.1 supports `SIGTERM` only. A config with another signal is
rejected. This matches the graceful termination path used by container
runtimes and most process managers.

## Can it test several requests at once?

Yes. Set `workload.concurrent` from 1 to 20 and use the `response-headers`
start barrier. Every request must be active before the signal and must finish
with the expected response.

A `probe` barrier supports one request because a shared probe cannot identify
which of several operations started.

## Why does the CLI exit with code 2 and no SC code?

The test did not run. Exit code `2` is used for bad command-line arguments,
missing or invalid JSON, and config validation errors. The stderr message
starts with `shutdown-check:`.

Fix that message first. SC codes are produced only after a valid test starts.
See [troubleshooting](https://shutdown.jscrate.dev/docs/troubleshooting#the-cli-exits-with-code-2).

## How should I choose the shutdown deadline?

The deadline must cover the slowest valid request and cleanup after `SIGTERM`,
with a margin. It must also stay below the platform's forced-kill deadline.

For Kubernetes, subtract `preStop` time from
`terminationGracePeriodSeconds`. Do not use a longer deadline to hide work
that can hang forever; add operation and cleanup timeouts.

## What should I run in CI?

Build the application, then run:

```bash
npx shutdown-check test --json --junit shutdown-result.xml
```

Exit code `1` fails the job for a shutdown problem. The JUnit report can be
published with other test results. Use a dedicated port and isolated test data.

## Related

- [Quick start](https://shutdown.jscrate.dev/docs/quick-start)
- [Configuration reference](https://shutdown.jscrate.dev/docs/configuration)
- [Diagnostic codes](https://shutdown.jscrate.dev/docs/codes)
- [Compatibility and limits](https://shutdown.jscrate.dev/docs/compatibility)
- [Troubleshooting](https://shutdown.jscrate.dev/docs/troubleshooting)
