# Shutdown Check > Test Node.js graceful shutdown in CI: shutdown-check sends SIGTERM to your real service mid-request and verifies in-flight work finishes before it exits. Shutdown Check documents `shutdown-check`, a CLI and Node API that tests whether a Node.js HTTP service shuts down gracefully. It is a black-box tester, not a shutdown-handler library: it launches the real service command, waits for its readiness route, starts slow HTTP requests, sends SIGTERM while they are in flight, and verifies that they finish with the expected response, that readiness is withdrawn and new requests are rejected (optional), and that the process exits with the expected code before a deadline and closes its port. - Install: `npm install --save-dev shutdown-check`, then `npx shutdown-check init` (writes shutdown-check.json) and `npx shutdown-check test`. Requires Node.js 22 or newer on macOS or Linux. Zero runtime dependencies; ESM and CommonJS. - Results: a timeline in the terminal, `--json` for the full result, `--junit FILE` for CI. Exit code 0 passed, 1 shutdown check failed, 2 setup or configuration error. - Diagnostic codes: SC000 means passed; SC001–SC312 and SC999 name the stage that failed. Each has a page under /docs/codes with its message and the fix. - Out of scope: databases, queues, WebSockets, HTTP/2, Kubernetes itself and Windows. - Every page below is markdown. Append `.md` to any docs URL to get the same. - Everything in one file: https://shutdown.jscrate.dev/llms-full.txt - Source: https://github.com/re-sohail/shutdown-check · Package: https://www.npmjs.com/package/shutdown-check ## Overview - [Quick start](https://shutdown.jscrate.dev/docs/quick-start.md): Install shutdown-check, create a config, and test that your Node.js server finishes in-flight HTTP requests and exits cleanly when it receives SIGTERM. - [How it works](https://shutdown.jscrate.dev/docs/how-it-works.md): How shutdown-check tests graceful shutdown: it launches your real server, holds a request open, sends SIGTERM and checks the response, exit and port. - [Comparison](https://shutdown.jscrate.dev/docs/comparison.md): Graceful shutdown testing tools compared: shutdown-check next to terminus, http-terminator, unit tests, kill-and-curl scripts and staging-only checks. - [FAQ](https://shutdown.jscrate.dev/docs/faq.md): Node.js graceful shutdown FAQ: SIGTERM, server.close(), in-flight requests, frameworks, Docker and Kubernetes, and what shutdown-check does and does not test. ## Guides - [Graceful shutdown in Node.js](https://shutdown.jscrate.dev/docs/guides/graceful-shutdown-nodejs.md): Node.js graceful shutdown: handle SIGTERM with server.close() in node:http, Express and Fastify, avoid the common mistakes, and verify it with shutdown-check. - [In-flight work and start barriers](https://shutdown.jscrate.dev/docs/in-flight-work.md): Test in-flight requests during shutdown: use a start barrier, response headers or a probe route, to prove work is running when SIGTERM arrives. - [Readiness and draining traffic](https://shutdown.jscrate.dev/docs/guides/readiness-and-draining.md): Make your readiness probe during shutdown return 503, reject new requests while old ones drain, and verify both with shutdown-check's drain checks. - [Kubernetes and containers](https://shutdown.jscrate.dev/docs/guides/kubernetes.md): Kubernetes graceful shutdown for Node.js: how pods stop, preStop and terminationGracePeriodSeconds, PID 1 in Docker, and a matching shutdown-check config. - [Tests with node:test or Vitest](https://shutdown.jscrate.dev/docs/guides/test-runners.md): Test graceful shutdown with node:test or Vitest: call checkShutdown from a test, set a long enough timeout, assert the result and print the timeline. - [CI](https://shutdown.jscrate.dev/docs/ci.md): Run a graceful shutdown test in CI with shutdown-check: GitHub Actions and GitLab CI examples, JUnit reports, exit codes, and a dedicated port per job. ## Reference - [CLI](https://shutdown.jscrate.dev/docs/cli.md): The shutdown-check CLI reference: the init and test commands, every flag, how the config file is found, the text output and the 0, 1 and 2 exit codes. - [Configuration](https://shutdown.jscrate.dev/docs/configuration.md): Every shutdown-check config field in shutdown-check.json: command, baseUrl, readiness, workload, start barrier and shutdown, with defaults, ranges and errors. - [Node API](https://shutdown.jscrate.dev/docs/node-api.md): The shutdown-check Node API: run a check from a test with checkShutdown, validate configs, build a custom runner with runCheck and write JUnit XML. - [Output and reports](https://shutdown.jscrate.dev/docs/output.md): What shutdown-check prints and writes: the text timeline, every timeline event, the --json result, the shutdown-check JUnit report and the exit codes. - [Compatibility and limits](https://shutdown.jscrate.dev/docs/compatibility.md): shutdown-check compatibility: Node.js 22 or later on macOS and Linux, ESM and CommonJS, any HTTP/1 framework, local HTTP, SIGTERM only, and what it skips. - [Troubleshooting](https://shutdown.jscrate.dev/docs/troubleshooting.md): shutdown-check troubleshooting by symptom: config errors, a busy port, a service that never gets ready, no in-flight work, hung or cut-off requests. ## Diagnostic codes - [All codes](https://shutdown.jscrate.dev/docs/codes.md): The shutdown-check diagnostic codes: what each SC code means, the stage of the check it comes from, and what to fix, from SC000 (pass) to SC999. - [SC000 Graceful shutdown verified](https://shutdown.jscrate.dev/docs/codes/sc000.md): SC000 (graceful shutdown verified) is the pass result: what shutdown-check proved about your service, what it does not cover, and how to keep it in CI. - [SC001 Port already in use](https://shutdown.jscrate.dev/docs/codes/sc001.md): SC001 (port already in use) means something answered on the configured port before shutdown-check launched your service. Find what holds it and fix it. - [SC002 No launch command](https://shutdown.jscrate.dev/docs/codes/sc002.md): SC002 (no launch command) means runCheck got a config with an empty command array. Why the CLI shows a config error instead, and how to fix it. - [SC100 Service never became ready](https://shutdown.jscrate.dev/docs/codes/sc100.md): SC100 (service never became ready) means the readiness route did not return its expected status before readiness.timeoutMs. The causes and how to fix each. - [SC101 Service exited before it was ready](https://shutdown.jscrate.dev/docs/codes/sc101.md): SC101 (service exited before it was ready) means your command crashed, exited or failed to start before readiness passed. Read stderr, then fix the command. - [SC110 Start probe was already active](https://shutdown.jscrate.dev/docs/codes/sc110.md): SC110 (start probe was already active) means the probe start barrier did not return inactiveStatus before work began. Fix the probe route or its statuses. - [SC111 Work was never in flight](https://shutdown.jscrate.dev/docs/codes/sc111.md): SC111 (work was never in flight) means the workload finished, or never showed it started, before SIGTERM. Use a slow streaming endpoint or a probe barrier. - [SC112 Exited before SIGTERM](https://shutdown.jscrate.dev/docs/codes/sc112.md): SC112 (exited before SIGTERM) means the service or a work request finished in the gap between the start barrier and the signal. Make the workload run longer. - [SC113 SIGTERM could not be delivered](https://shutdown.jscrate.dev/docs/codes/sc113.md): SC113 (SIGTERM could not be delivered) means the operating system refused the signal to your service process. Why it happens and how to run the check. - [SC114 Second SIGTERM could not be delivered](https://shutdown.jscrate.dev/docs/codes/sc114.md): SC114 (second SIGTERM could not be delivered) means work had already ended when repeatSignalAfterMs fired. Lower the delay or make the workload run longer. - [SC200 In-flight request did not finish](https://shutdown.jscrate.dev/docs/codes/sc200.md): SC200 (in-flight request did not finish) means a request running at SIGTERM did not complete before the shutdown deadline. The causes and how to fix them. - [SC201 In-flight request was interrupted](https://shutdown.jscrate.dev/docs/codes/sc201.md): SC201 (in-flight request was interrupted) means a request running at SIGTERM was cut off before its response ended. Stop exiting or closing sockets early. - [SC202 In-flight request got the wrong status](https://shutdown.jscrate.dev/docs/codes/sc202.md): SC202 (in-flight request got the wrong status) means a request running at SIGTERM finished with a status other than workload.status. Find what changed it. - [SC203 In-flight response body was wrong](https://shutdown.jscrate.dev/docs/codes/sc203.md): SC203 (in-flight response body was wrong) means a request running at SIGTERM finished without the workload.bodyIncludes text. Check the handler and config. - [SC300 Service did not exit in time](https://shutdown.jscrate.dev/docs/codes/sc300.md): SC300 (service did not exit in time) means the process was still running at the shutdown deadline. Find the open handle keeping Node alive and close it. - [SC301 Service exited with the wrong code](https://shutdown.jscrate.dev/docs/codes/sc301.md): SC301 (service exited with the wrong code) means the process exited with a code other than shutdown.exitCode, or was killed by a signal. How to fix both. - [SC302 Port still open after exit](https://shutdown.jscrate.dev/docs/codes/sc302.md): SC302 (port still open after exit) means the launched process exited but the HTTP port still accepted connections: a child server kept running. How to fix it. - [SC310 Readiness was not withdrawn](https://shutdown.jscrate.dev/docs/codes/sc310.md): SC310 (readiness was not withdrawn) means the readiness route still reported ready after SIGTERM, up to the deadline. Return 503 or stop listening on SIGTERM. - [SC311 New request was accepted during drain](https://shutdown.jscrate.dev/docs/codes/sc311.md): SC311 (new request was accepted during drain) means a new request sent after readiness was withdrawn was not rejected. Return 503 or stop listening. - [SC312 Work finished too soon to test rejection](https://shutdown.jscrate.dev/docs/codes/sc312.md): SC312 (work finished too soon to test rejection) means in-flight work ended before the new request could be sent during drain. Use a longer-running workload. - [SC999 Unexpected error](https://shutdown.jscrate.dev/docs/codes/sc999.md): SC999 (unexpected error) means shutdown-check itself hit an error it did not plan for. Read the message, check the config, or report it with the timeline. ## Optional - [Releases](https://shutdown.jscrate.dev/docs/releases.md): shutdown-check releases: the changelog for 1.0.1 and 1.0.0, the milestones built into 1.0, and how to upgrade and check the version you have installed. - [About](https://shutdown.jscrate.dev/docs/about.md): About shutdown-check: why it exists, what it is and is not, who maintains it, its MIT license, and how to report a problem with a useful, secret-free issue. - [GitHub releases](https://github.com/re-sohail/shutdown-check/releases): Full release notes for every version.