# 快速开始

> 安装 shutdown-check 并生成配置，验证你的 Node.js 服务在收到 SIGTERM 后，能处理完进行中的 HTTP 请求并正常退出。

Source: https://shutdown.jscrate.dev/zh/docs/quick-start
Last updated: 2026-09-23

shutdown-check 会启动你的 Node.js 服务，发起一个请求，在请求还没结束时发送 `SIGTERM`，然后观察接下来发生了什么。结果为通过，说明请求处理完成、进程按时退出、端口已经关闭。

## 准备工作

你需要准备：

- Node.js 22 或更高版本
- macOS 或 Linux
- 一个本地 HTTP/1 服务
- 一个就绪检查（readiness）路由，例如 `/health`
- 一个耗时足够长的路由，保证请求还在处理时能收到 `SIGTERM`

这个包适用于 node:http、Express、Fastify、NestJS 以及其他 Node.js 框架。它不会给你的应用添加关闭逻辑，只测试你已经写好的关闭逻辑。如果要用于 HTTPS、HTTP/2、WebSocket、Windows 或远程服务，请先阅读[兼容性与限制](https://shutdown.jscrate.dev/zh/docs/compatibility)。

## 1. 安装 shutdown-check

把 shutdown-check 安装为开发依赖：

```bash
npm install --save-dev shutdown-check
```

这个包没有运行时依赖，也不需要随生产应用一起发布。

## 2. 创建配置

在项目根目录运行初始化命令：

```bash
npx shutdown-check init
```

该命令会生成 `shutdown-check.json`。如果文件已存在，不会覆盖。生成的内容如下：

```json title="shutdown-check.json"
{
  "command": ["node", "server.js"],
  "cwd": ".",
  "baseUrl": "http://127.0.0.1:3000",
  "readiness": { "path": "/health", "status": 200, "timeoutMs": 10000 },
  "workload": {
    "path": "/slow",
    "method": "GET",
    "status": 200,
    "started": { "type": "response-headers", "timeoutMs": 5000 }
  },
  "shutdown": { "deadlineMs": 10000, "exitCode": 0 }
}
```

修改以下几项：

| 字段             | 填写内容                                         |
| ---------------- | ------------------------------------------------ |
| `command`        | 直接启动构建产物的命令                           |
| `baseUrl`        | 专门留给这次测试的本地端口                       |
| `readiness.path` | 服务就绪时返回预期状态码的路由                   |
| `workload.path`  | 耗时足够长、能在处理过程中收到关闭信号的路由     |

尽量直接启动服务，例如 `["node", "dist/server.js"]`。如果外面包了一层 shell 或包管理器，信号可能被它们收到，而不是服务本身。

## 3. 准备可测试的请求路由

初始配置使用 `response-headers` 启动确认（start barrier）。测试请求对应的路由必须先发出响应头，并保持响应体未结束。这样 shutdown-check 才能在发送 `SIGTERM` 之前确认请求确实正在处理。

下面是一个与初始配置对应的完整服务：

```js title="server.js"
const http = require("node:http");

const port = Number(process.env.PORT ?? 3000);

const server = http.createServer((request, response) => {
  if (request.url === "/health") {
    response.writeHead(200, { "content-type": "text/plain" });
    response.end("ok");
    return;
  }

  if (request.url === "/slow") {
    response.writeHead(200, { "content-type": "text/plain" });
    response.flushHeaders();
    setTimeout(() => response.end("work complete\n"), 2000);
    return;
  }

  response.writeHead(404).end();
});

server.listen(port, "127.0.0.1", () => {
  console.log(`listening on http://127.0.0.1:${port}`);
});

process.on("SIGTERM", () => {
  console.log("SIGTERM received; closing the server");
  server.close((error) => {
    if (error) {
      console.error(error);
      process.exitCode = 1;
    }
  });
});
```

`response.flushHeaders()` 会立即发出 `200` 响应头，响应体在两秒后才结束。收到 `SIGTERM` 时，`server.close()` 停止接受新连接，并等待尚未结束的响应完成。

如果你的处理函数要等工作全部完成后才发送任何内容，请改用 [probe 启动确认](https://shutdown.jscrate.dev/zh/docs/in-flight-work#use-the-probe-barrier)。普通的、很快返回的路由不适用：请求可能在信号到达前就已结束，结果会是 [SC111](https://shutdown.jscrate.dev/zh/docs/codes/sc111)。

## 4. 运行测试

```bash
npx shutdown-check test
```

测试会依次：

1. 检查配置的端口是否空闲
2. 在独立的进程组中启动 `command`
3. 等待就绪检查通过
4. 发出测试请求，并确认请求正在处理
5. 发送 `SIGTERM`
6. 等待响应完成和进程退出
7. 检查端口是否已关闭

测试通过时命令以 `0` 退出；关闭检查失败时以 `1` 退出；环境或配置无效、导致测试无法运行时以 `2` 退出。

## 5. 看懂通过结果

上面的服务会输出类似下面的结果。耗时和进程 ID 每次都会不同。

```text
PASS SC000: Graceful shutdown verified

Timeline:
  +    5 ms  process launched — pid=73661
  +  112 ms  service ready — HTTP 200
  +  112 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
  + 2118 ms  work request finished — #1 HTTP 200
  + 2125 ms  process exited — code=0, signal=none
  + 2126 ms  shutdown verified — work completed and service exited before deadline
```

关键看这几点的顺序：

- `work confirmed active` 出现在 `signal sent` 之前
- 请求在信号之后才完成
- 进程以退出码 `0` 退出
- `shutdown verified` 出现在最后

[SC000](https://shutdown.jscrate.dev/zh/docs/codes/sc000) 是通过时的诊断码。每个时间线事件的含义见[输出参考](https://shutdown.jscrate.dev/zh/docs/output)。

## 6. 看一次真实的失败

删掉 `SIGTERM` 处理函数，再运行一次。Node.js 会按默认的信号行为立即退出，正在处理的请求被直接中断：

```text
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: aborted

Service stdout (last 8 KiB):
listening on http://127.0.0.1:3000
```

第一行给出固定不变的诊断码。打开 [SC201](https://shutdown.jscrate.dev/zh/docs/codes/sc201) 可以查看原因和修复方法。失败时，CLI 还会附上服务 stdout 和 stderr 的最后 8 KiB。

配置无效时输出不一样：以 `shutdown-check:` 开头，没有 SC 诊断码和时间线，退出码为 `2`：

```text
shutdown-check: Cannot read JSON config /path/shutdown-check.json: Error: ENOENT: no such file or directory, open '/path/shutdown-check.json'
```

如果命令没能跑出正常的测试结果，请参考[故障排查](https://shutdown.jscrate.dev/zh/docs/troubleshooting)。

## 7. 加强检查

初始配置只覆盖一个请求、进程退出和端口关闭。你还可以验证多个请求、响应内容、撤回就绪状态、拒绝新请求，以及重复发送信号：

```json title="shutdown-check.json"
{
  "command": ["node", "server.js"],
  "baseUrl": "http://127.0.0.1:3000",
  "readiness": { "path": "/health" },
  "workload": {
    "path": "/slow",
    "bodyIncludes": "work complete",
    "concurrent": 2,
    "started": { "type": "response-headers" }
  },
  "shutdown": {
    "deadlineMs": 10000,
    "readinessWithdrawal": true,
    "newRequests": { "path": "/health" },
    "repeatSignalAfterMs": 500
  }
}
```

示例服务同样能通过就绪检查和新请求检查，因为 `server.close()` 会拒绝新连接。如果你的应用在排空期间仍保持监听，也可以改为返回 `503`，参见[就绪检查与排空](https://shutdown.jscrate.dev/zh/docs/guides/readiness-and-draining)。

## 8. 在 CI 中运行

先构建服务，然后运行：

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

非零退出码会让任务失败。JUnit 文件可以作为测试报告发布，JSON 则把完整结果保留在任务日志里。[CI 指南](https://shutdown.jscrate.dev/zh/docs/ci)提供了 GitHub Actions 和 GitLab 的示例。

## 相关内容

- [配置参考](https://shutdown.jscrate.dev/zh/docs/configuration)
- [检查的工作原理](https://shutdown.jscrate.dev/zh/docs/how-it-works)
- [Node.js 中的优雅关闭](https://shutdown.jscrate.dev/zh/docs/guides/graceful-shutdown-nodejs)
- [进行中的请求与启动确认](https://shutdown.jscrate.dev/zh/docs/in-flight-work)
- [全部诊断码](https://shutdown.jscrate.dev/zh/docs/codes)
