Shutdown Check

Search documentation

Find a page or section

Build the service, run a real shutdown, and publish the result with the rest of your tests.

Run shutdown-check after building your application. The CLI's exit code fails the job, while JSON and JUnit preserve the diagnostic code, timeline, and captured service output.

Prepare the project

Before adding CI configuration:

  1. Run npx shutdown-check test locally.
  2. Commit shutdown-check.json.
  3. Point command at the built entry file.
  4. Reserve a port for this test.
  5. Use isolated database, queue, and file resources.
  6. Make sure the workload route is deterministic.

shutdown-check starts and stops the service itself. Do not start the same service in an earlier CI step or service container on the configured port.

GitHub Actions

.github/workflows/shutdown.yml
name: Graceful shutdown
 
on:
  push:
    branches: [main]
  pull_request:
 
jobs:
  shutdown-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
 
      - uses: actions/setup-node@v5
        with:
          node-version: 22
          cache: npm
 
      - run: npm ci
      - run: npm run build
 
      - name: Test graceful shutdown
        run: npx shutdown-check test --json --junit shutdown-result.xml
 
      - name: Save shutdown report
        uses: actions/upload-artifact@v4
        if: ${{ !cancelled() }}
        with:
          name: shutdown-check-report
          path: shutdown-result.xml
          if-no-files-found: ignore

--json keeps the full structured result in the job log. Remove it if you prefer the readable text timeline.

The artifact step uses if: !cancelled() so it still runs after a failed check. if-no-files-found: ignore handles setup errors, which exit with code 2 before a JUnit result exists.

To show the result directly in the pull-request checks, pass shutdown-result.xml to a JUnit reporter action instead of, or in addition to, uploading it.

GitLab CI

.gitlab-ci.yml
shutdown-check:
  image: node:22
  script:
    - npm ci
    - npm run build
    - npx shutdown-check test --junit shutdown-result.xml
  artifacts:
    when: always
    reports:
      junit: shutdown-result.xml
    paths:
      - shutdown-result.xml

GitLab reads the report and adds the test case to the merge request. The artifact remains downloadable after failure because when: always is set.

Exit codes in CI

Exit codeMeaning
0passed
1shutdown check failed
2setup/configuration error
CodeCI meaningJUnit file
0The shutdown behavior passedWritten when requested
1The test ran and a shutdown check failedWritten when requested
2Arguments, config, or setup prevented the testNot written

Do not add || true to the shutdown command. That hides the exit code and can let a broken deployment behavior merge.

Give parallel jobs separate ports

shutdown-check fails with SC001 if anything already owns baseUrl. Give each job or matrix entry a different port and pass it to the service through env.

shutdown-check.json
{
  "env": { "PORT": "3510" },
  "baseUrl": "http://127.0.0.1:3510"
}

For dynamic matrices, generate a small config in the job or call the Node API with a port derived from the matrix value. Do not run concurrent shutdown tests against the same database records or queue messages.

Choose CI timeouts

The job must allow enough time for:

  • dependency installation and build;
  • readiness.timeoutMs;
  • workload.started.timeoutMs;
  • shutdown.deadlineMs;
  • a small process and runner overhead.

A test-runner timeout that ends first removes the useful shutdown result. Keep the outer timeout above the sum of the shutdown-check timeouts, while keeping the shutdown deadline realistic for production.

Diagnose a failed job

  1. Read the SC code in the first output line.
  2. Find the last successful timeline event.
  3. Read captured stderr and stdout.
  4. Open the page for the diagnostic code.
  5. Reproduce with the same build command and environment locally.

Use troubleshooting when the failure is timing-related or occurs before the service becomes ready.

Run through an existing test suite

If CI already publishes node:test or Vitest results, call checkShutdown() from a test file. The existing runner can report the assertion, and you can print the timeline on failure.

See tests with node:test and Vitest for complete examples and timeout guidance.

Supported runners

Use Linux or macOS with Node.js 22 or later. Windows runners are not supported because shutdown-check depends on POSIX signals and process groups. A Linux container runner is supported when it can start child processes and bind a local port.