Shutdown Check

搜索文档

查找页面或章节

构建服务,执行一次真实的关闭,再把结果和其他测试一起发布。

在应用构建完成后运行 shutdown-check。CLI 的退出码决定 job 是否失败;JSON 和 JUnit 输出会保留诊断码、时间线和捕获到的服务输出。

准备项目

添加 CI 配置之前,先完成以下准备:

  1. 在本地运行 npx shutdown-check test。
  2. 提交 shutdown-check.json。
  3. 把 command 指向构建后的入口文件。
  4. 为这个测试预留一个端口。
  5. 使用相互隔离的数据库、队列和文件资源。
  6. 确保测试请求所用路由的行为是确定的。

shutdown-check 会自己启动和停止服务。不要在前面的 CI 步骤或 service container 中,在配置的端口上启动同一个服务。

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 会把完整的结构化结果写进 job 日志。如果你更想看可读的文本时间线,去掉这个参数即可。

上传 artifact 的步骤使用了 if: !cancelled(),所以检查失败后这一步仍会执行。if-no-files-found: ignore 用来处理环境或配置错误:这类错误以退出码 2 结束,此时还没有生成 JUnit 结果。

如果想在 pull request 的检查结果里直接显示测试结果,可以把 shutdown-result.xml 交给一个 JUnit reporter action,用来替代上传,或者和上传同时使用。

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 会读取这份报告,并把测试用例显示在 merge request 中。由于设置了 when: always,即使失败,artifact 仍然可以下载。

CI 中的退出码

退出码含义
0通过
1关闭检查失败
2环境或配置错误
退出码在 CI 中的含义JUnit 文件
0关闭行为通过检查指定时写入
1测试已运行,但有一项关闭检查失败指定时写入
2参数、配置或环境问题导致测试无法运行不写入

不要在关闭测试命令后面加 || true。这样会吞掉退出码,可能让破坏部署行为的改动被合并。

为并行 job 分配不同端口

只要 baseUrl 已被其他进程占用,shutdown-check 就会以 SC001 失败。给每个 job 或 matrix 条目分配不同的端口,并通过 env 传给服务。

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

如果 matrix 是动态生成的,可以在 job 中生成一份小配置,或者调用 Node API,并用 matrix 的值推导出端口。不要让并发的关闭测试操作同一批数据库记录或队列消息。

设置 CI 超时

job 的超时时间必须留够以下各项的耗时:

  • 安装依赖和构建
  • readiness.timeoutMs
  • workload.started.timeoutMs
  • shutdown.deadlineMs
  • 少量的进程和 runner 开销

如果测试运行器的超时先触发,你就拿不到有价值的关闭检查结果。外层超时要大于 shutdown-check 各项超时之和,同时关闭截止时间仍要贴近生产环境的实际情况。

排查失败的 job

  1. 看输出第一行的 SC 码。
  2. 找到最后一个成功的时间线事件。
  3. 查看捕获到的 stderr 和 stdout。
  4. 打开对应诊断码的页面。
  5. 在本地用相同的构建命令和环境复现。

如果失败和时序有关,或者发生在服务就绪之前,请参考故障排查。

在现有测试套件中运行

如果 CI 已经在发布 node:test 或 Vitest 的结果,可以在测试文件中调用 checkShutdown()。这样现有的测试运行器就能报告断言结果,你也可以在失败时打印时间线。

完整示例和超时设置建议见使用 node:test 和 Vitest 测试。

支持的 runner

请使用 Linux 或 macOS,并搭配 Node.js 22 或更高版本。shutdown-check 依赖 POSIX 信号和进程组,因此不支持 Windows runner。Linux 容器 runner 只要能启动子进程并绑定本地端口,也同样支持。