Shutdown Check

Search documentation

Find a page or section

Choose what implements shutdown, what tests it, and what each approach can prove.

Shutdown libraries and shutdown tests solve different problems. A library adds signal handling and cleanup to your service. shutdown-check starts the real service and tests whether that behavior works from the outside.

What is shutdown-check for?

Use shutdown-check when you already have a signal handler—written by you, your framework, or a library—and want to verify the complete process lifecycle.

It checks:

  • the production-like start command;
  • readiness;
  • a real active HTTP request;
  • SIGTERM delivery;
  • response completion;
  • optional traffic draining;
  • process exit and exit code;
  • final port closure.

It does not install a signal handler or close application resources for you.

Shutdown libraries

Libraries such as @godaddy/terminus, http-terminator, lightship, and close-with-grace run inside the application. They may register signal listeners, close HTTP servers, manage timeouts, and provide cleanup hooks.

Use a library when you need an implementation. Then test the configured result with shutdown-check. A correct library can still be used incorrectly: the wrong server object may be closed, cleanup may run in the wrong order, or the production command may prevent signals from reaching Node.js.

Framework shutdown hooks

Fastify, NestJS, and other frameworks provide shutdown APIs. These are also implementations, not end-to-end tests.

Framework tests often call a close method directly. A deployment sends a signal to a process. shutdown-check covers the signal listener, command, framework, open socket, and final exit together.

Unit tests

A unit test can call the shutdown function and assert that mocked dependencies were closed.

Strengths:

  • fast;
  • precise failure location;
  • easy to cover error branches;
  • suitable for database and queue cleanup logic.

Limits:

  • usually no real child process;
  • no operating-system signal;
  • mocked HTTP connections;
  • no proof that the production start command exits;
  • no check for orphaned child processes.

Keep unit tests. Add a black-box test for the process behavior they cannot cover.

Shell scripts with kill and curl

A custom script can start the app, use curl, send kill -TERM, and inspect the exit.

This approach can work, but reliable synchronization is difficult. A fixed sleep does not prove that a request was active when the signal arrived. The script must also handle concurrent requests, response bodies, timeouts, process groups, cleanup, exit codes, and CI reports.

shutdown-check packages those details into a repeatable config and stable diagnostic codes.

Staging and Kubernetes tests

A staging deployment is the only place to test cluster-level behavior such as endpoint propagation, ingress timing, sidecars, and preStop hooks.

It is also slower and harder to reproduce. Requests may not be active during termination, and a successful rollout does not prove that no request was dropped.

Use shutdown-check before deployment for deterministic server behavior, then use staging tests for infrastructure behavior.

Comparison table

Capabilityshutdown-checkShutdown libraryUnit testShell scriptStaging test
Adds shutdown behaviorNoYesNoNoNo
Runs the real start commandYesN/AUsually noYesYes
Sends a real SIGTERMYesHandles itUsually noYesYes
Proves work is active before the signalYesNoWith mocksHardHard
Verifies response status and bodyYesNoYesPossiblePossible
Checks readiness withdrawalOptionalMay implementWith mocksPossibleYes
Checks process exit and final portYesNoNoPossibleIndirect
Checks databases and queues directlyNoMay close themYesCustomCustom
Covers cluster routing and sidecarsNoNoNoNoYes
Produces stable failure codesYesNoTest namesCustomCustom

Which approach should I use?

For most services:

  1. Use framework features, a library, or a small handler to implement shutdown.
  2. Unit-test application-specific cleanup and error paths.
  3. Run shutdown-check locally and in CI for the process and HTTP lifecycle.
  4. Test Kubernetes, proxy, and load-balancer behavior in staging.

These layers complement each other. Replacing all of them with one test leaves important behavior unverified.

When shutdown-check is not enough

Add another test when correctness depends on:

  • a database transaction after the HTTP response;
  • queue acknowledgement;
  • background jobs;
  • WebSockets or HTTP/2;
  • remote service coordination;
  • container or cluster termination order.

The compatibility page describes the boundary in more detail.