Shutdown Check

搜索文档

查找页面或章节

关于信号、进行中的请求、框架、容器和测试行为的解答。

这里整理了 Node.js 优雅关闭最常见的问题。需要完整代码或更深入的排查时,每个回答都附有对应的指南或参考页面链接。

Node.js 中的优雅关闭是什么?

优雅关闭(graceful shutdown)是指停止服务时,不打断已经开始的工作。收到 SIGTERM 后,服务不再接收新工作,处理完进行中的请求,关闭共享资源,并在平台的截止时间之前退出。

这套流程和具体应用相关,Node.js 不会替你实现。你需要添加信号处理函数,或者使用专门的关闭库,然后验证行为是否符合预期。Node.js 指南提供了 node:http、Express 和 Fastify 的完整示例。

shutdown-check 会让我的应用实现优雅关闭吗?

不会。shutdown-check 是测试工具,不是关闭处理库。它不会修改你的服务,也不在服务内部运行。

它会启动你配置的命令,发出一个真实请求,发送 SIGTERM,然后检查响应和进程。信号处理函数、资源关闭以及排空策略,仍然需要你自己实现和决定。

为什么 Node.js 收到 SIGTERM 会立即退出?

如果没有有效的监听器,信号会按默认行为终止进程,所有打开的 HTTP 连接都可能被切断。

在真正运行服务器的那个进程上注册监听器:

process.on("SIGTERM", () => {
  server.close((error) => {
    if (error) process.exitCode = 1;
  });
});

如果 Node.js 是由 shell 或包管理器的包装进程启动的,信号可能只到达包装进程。尽量直接启动,例如 node dist/server.js。

为什么 server.close() 一直不结束?

server.close() 会等待活跃连接结束。以下情况会让它看起来像卡住了:

  • 某个 HTTP 响应一直没有结束
  • 上游服务或数据库操作挂起
  • 客户端一直保持连接活跃
  • 应用关闭了请求仍在使用的依赖
  • 服务器关闭后,还有其他资源让 Node.js 保持运行

给回调、活跃的处理函数和每一步清理都加上日志,并为外部操作设置超时。请求一直不结束的情况见 SC200;请求都结束后进程仍不退出的情况见 SC300。

为什么测试提示测试请求始终未处于进行中?

说明测试请求在发送信号前就已结束,或者它的启动确认一直没有通过。没有进行中的工作,关闭测试就无法证明服务做了排空。

使用 response-headers 时,先发送响应头,并保持响应体不结束。使用 probe 时,让一个单独的路由在操作执行期间从未活跃变为活跃。详见进行中的工作与启动确认。

支持 Express、Fastify 或 NestJS 吗?

支持。shutdown-check 不依赖任何框架,它只启动一条命令,并通过本地 HTTP 通信。

  • Express 使用 app.listen() 返回的 Node.js 服务器。
  • Fastify 可以通过 fastify.close() 关闭。
  • NestJS 需要配置关闭钩子,并等待它们执行完成。

服务需要提供就绪检查路由和测试请求路由,并能响应 SIGTERM。各框架的具体实现见优雅关闭指南。

能测试数据库、队列或 WebSocket 吗?

不能直接测试。shutdown-check 只观察服务进程和 HTTP/1 响应。它看不到数据库或队列的内部状态,也不会建立 WebSocket 或 HTTP/2 会话。

如果响应内容能证明关键工作已经完成,可以使用 bodyIncludes。数据库事务、队列确认(ack)、后台任务、WebSocket,以及响应之后仍在继续的工作,需要另外编写针对应用的测试。

能在 Windows 上运行吗?

不能原生运行。这个工具依赖 POSIX 信号和进程组,因此支持 macOS 和 Linux。

在 Windows 开发机上,可以在 WSL、Linux 容器或 Linux CI 中运行。服务和测试必须运行在同一个受支持的环境中,并且能访问本地端口。

能在 Docker 或 Kubernetes 中运行吗?

可以,但有限制。它可以在装有 Node.js 22 或更高版本的 Linux 容器中运行,测试的是该容器内的服务进程和本地 HTTP 行为。

它不会模拟 Kubernetes 的 endpoint 移除、preStop、sidecar、ingress 或集群的终止宽限期(grace period)。请参考 Kubernetes 指南了解这些设置如何对应,其余行为放到预发布环境中测试。

它和 terminus 这类关闭库有什么区别?

terminus 这类库在服务内部实现关闭行为,shutdown-check 则从服务外部测试这些行为。

两者可以一起使用:用库注册处理函数、关闭资源,再用 shutdown-check 证明真实的启动命令、信号传递路径、进行中的请求、进程退出和端口关闭能够协同工作。对比页面还介绍了单元测试、脚本和预发布环境测试这几种方式。

shutdown-check 会发送 SIGINT 吗?

不会。1.0.1 版本只支持 SIGTERM,配置了其他信号会被拒绝。这与容器运行时和大多数进程管理器使用的优雅终止方式一致。

能同时测试多个请求吗?

可以。将 workload.concurrent 设为 1 到 20,并使用 response-headers 启动确认。每个请求都必须在发送信号前处于进行中,并以预期的响应结束。

probe 启动确认只支持一个请求,因为多个操作共用一个探测路由时,无法分辨是哪一个开始了。

为什么 CLI 以退出码 2 退出,却没有 SC 码?

说明测试根本没有运行。退出码 2 表示命令行参数错误、JSON 缺失或无效,以及配置校验失败。stderr 中的消息以 shutdown-check: 开头。

先根据这条消息修复问题。只有有效的测试开始运行后,才会产生 SC 码。详见故障排查。

关闭截止时间应该怎么设?

截止时间必须覆盖 SIGTERM 之后最慢的正常请求和清理所需的时间,并留出余量。同时,它必须小于平台强制终止进程的截止时间。

在 Kubernetes 中,用 terminationGracePeriodSeconds 减去 preStop 的耗时。不要靠拉长截止时间来掩盖可能永远挂起的工作,而应为操作和清理设置超时。

在 CI 中应该运行什么?

先构建应用,然后运行:

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

出现关闭问题时,退出码 1 会让任务失败。JUnit 报告可以和其他测试结果一起发布。请使用专用端口和隔离的测试数据。