Every shutdown-check run produces one result with a verdict, diagnostic code, message, timeline, duration, and captured service output. Choose text for people, JSON for scripts, or JUnit XML for CI reports.
Choose an output format
| Format | Command option | Destination | Best for |
|---|---|---|---|
| Text | default | stdout | Local debugging and CI logs |
| JSON | --json | stdout | Scripts and structured logs |
| JUnit XML | --junit FILE | file | CI test-report interfaces |
| Exit code | always | process | Passing or failing the caller |
You can write JUnit while printing either text or JSON:
npx shutdown-check test --json --junit shutdown-result.xmlRead the text output
A passing result contains a verdict and timeline:
PASS SC000: Graceful shutdown verified
Timeline:
+ 5 ms process launched — pid=67911
+ 113 ms service ready — HTTP 200
+ 113 ms work request sent — #1 GET /slow
+ 113 ms work request sent — #2 GET /slow
+ 114 ms work confirmed active — 2 response(s) sent headers; bodies still in progress
+ 114 ms signal sent — SIGTERM
+ 115 ms readiness withdrawn — HTTP 503
+ 115 ms new request rejected — HTTP 503
+ 2117 ms work request finished — #1 HTTP 200
+ 2117 ms work request finished — #2 HTTP 200
+ 2120 ms process exited — code=0, signal=none
+ 2121 ms shutdown verified — work completed and service exited before deadlineThe number after + is milliseconds since the run began. Read the lines in
order to see what happened before and after SIGTERM.
A failure ends with check failed:
FAIL SC201: In-flight request was interrupted: aborted
Timeline:
+ 6 ms process launched — pid=73692
+ 112 ms service ready — HTTP 200
+ 113 ms work request sent — #1 GET /slow
+ 113 ms work confirmed active — 1 response(s) sent headers; bodies still in progress
+ 113 ms signal sent — SIGTERM
+ 116 ms process exited — code=null, signal=SIGTERM
+ 116 ms work request finished — #1 aborted
+ 116 ms check failed — SC201: In-flight request was interrupted: abortedOpen the page for the code—in this case SC201—to see causes and fixes.
Service stdout and stderr
On a failed check, text output adds the last 8 KiB of each non-empty service stream:
Service stderr (last 8 KiB):
Error: database close timed out
Service stdout (last 8 KiB):
SIGTERM received
closing HTTP serverEarlier output is discarded when a stream grows beyond 8 KiB. Keep shutdown logs concise and write important state near the failure.
The service output is captured, not streamed live. It appears after the result so the timeline remains readable.
Timeline events
| Event | Meaning |
|---|---|
process launched | The configured command started |
service ready | The readiness route returned its expected status |
work request sent | A workload request was opened |
work confirmed active | The selected start barrier passed |
signal sent | The first SIGTERM was delivered |
signal repeated | The optional second SIGTERM was delivered |
readiness withdrawn | The readiness route stopped reporting ready |
new request rejected | New work returned an allowed status or connection refusal |
work request finished | A workload response completed or failed |
process exited | The launched process stopped |
shutdown verified | Every configured check passed |
check failed | The run ended with the displayed diagnostic code |
An event appears only when that part of the config runs. For example,
readiness withdrawn is absent unless shutdown.readinessWithdrawal is
enabled.
JSON output
Run:
npx shutdown-check test --jsonThe command prints one JSON object. A shortened passing example:
{
"pass": true,
"code": "SC000",
"message": "Graceful shutdown verified",
"startedAt": "2026-09-23T10:00:00.000Z",
"durationMs": 2121,
"timeline": [
{ "ms": 5, "event": "process launched", "detail": "pid=67911" },
{ "ms": 114, "event": "signal sent", "detail": "SIGTERM" },
{
"ms": 2121,
"event": "shutdown verified",
"detail": "work completed and service exited before deadline"
}
],
"stdout": "",
"stderr": ""
}| Option | Type | Default | Description |
|---|---|---|---|
| pass* | boolean | — | true only for SC000. |
| code* | string | — | The diagnostic code: SC000 on a pass, the first failure otherwise. |
| message* | string | — | What happened, in one sentence, with the values observed. |
| timeline* | TimelineEvent[] | — | Every step of the check in order, with milliseconds since it started. |
| stdout* | string | — | The last 8 KiB the service wrote to stdout. |
| stderr* | string | — | The last 8 KiB the service wrote to stderr. |
The timeline array contains:
| Option | Type | Default | Description |
|---|---|---|---|
| ms* | number | — | Milliseconds since the check started, rounded. |
| event* | string | — | What happened: "process launched", "service ready", "signal sent", "work request finished", "process exited" and so on. |
| detail | string | — | The values behind it, such as "HTTP 503" or "code=0, signal=none". |
JSON uses the same exit codes as text. A failure still exits with 1, so a
shell step may need to preserve stdout before reacting to the exit.
JUnit report
Run:
npx shutdown-check test --junit reports/shutdown.xmlThe parent directory must exist. shutdown-check writes one test suite with one test case:
- a pass has no failure element;
- a failed shutdown adds the diagnostic code and message as the failure;
- the timeline is included in system output;
- captured service stdout and stderr are included when available;
- the suite time uses the run duration.
The default suite name is shutdown-check. From the Node API, pass a second
argument to junitXml(result, name) to choose another name.
The report is written before the CLI prints text or JSON. A normal check
failure therefore still produces the file. A setup or config error produces
no report because no CheckResult exists.
Exit codes
| Exit code | Meaning |
|---|---|
| 0 | passed |
| 1 | shutdown check failed |
| 2 | setup/configuration error |
| Code | Meaning | Output available |
|---|---|---|
0 | The configured shutdown contract passed | Text/JSON and optional JUnit |
1 | The test ran and returned a failing SC code | Text/JSON and optional JUnit |
2 | Arguments, setup, or config stopped the run | Error on stderr; no JUnit result |
CI should fail on any nonzero code. Treat 2 as a broken test setup and 1
as a service behavior that needs investigation.
Use the result from code
checkShutdown() and runCheck() return the same CheckResult object used by
JSON output. junitXml() creates the same XML as the CLI.
import { checkShutdown, junitXml } from "shutdown-check";
const result = await checkShutdown(config);
const xml = junitXml(result, "orders-api shutdown");See the Node API for a complete custom runner.