Express 应用健康检查与优雅关闭(Graceful Shutdown)实战指南
文档教程技术博客【免费下载链接】expressjs.comThe Express.js Website项目地址https://gitcode.com/gh_mirrors/ex/expressjs.com点击查看免费下载导读部署新版 Express 应用时进程管理器会向旧实例发送SIGTERM信号若应用直接退出正在处理的请求可能被中断、数据库连接与文件锁得不到释放造成数据不一致。本指南以 expressjs.com 官方文档中的《Health Checks and Graceful Shutdown》为核心讲解如何通过监听SIGTERM、调用server.close()实现优雅关闭并配合/healthz、/readyz健康检查端点与 Kubernetes 的liveness、readiness探针集成让应用在滚动部署、负载均衡场景下实现零中断切换。读完本文你将掌握一套可落地的生产级平滑下线 健康探测方案。一、为什么需要优雅关闭在部署新版本时编排系统如 Kubernetes或进程管理器如 systemd、PM2需要终止旧版本实例。标准流程是管理器先向应用进程发送SIGTERM信号通知它即将被杀死随后在宽限期grace period结束后若进程仍未退出再发送SIGKILL强制结束。这个过程中应用的理想行为是依次完成四件事停止接收新请求——不再接受新的连接或请求完成所有正在处理的请求——让进行中的响应自然返回避免客户端收到被截断的响应清理已使用的资源——包括数据库连接池、文件锁、消息队列订阅等退出进程——进程自行退出而不是被SIGKILL强杀。如果不做任何处理进程收到SIGTERM后默认直接退出正在写的响应被中断数据库连接被操作系统回收长时间持有的文件锁可能残留甚至在事务中途退出导致数据不一致。这就是优雅关闭要解决的问题。本主题属于官方文档 Advanced 章节 下的生产实践系列与 生产最佳实践性能与可靠性、生产最佳实践安全 同属一个文档体系本文是其可靠性维度的核心一篇。二、优雅关闭的最小实现2.1 官方示例代码expressjs.com 官方文档给出的最小实现如下见 英文原文 与 中文翻译版const server app.listen(port); process.on(SIGTERM, () { debug(SIGTERM signal received: closing HTTP server); server.close(() { debug(HTTP server closed); }); });这段代码只有两个关键点app.listen(port)的返回值被保存到server变量通过process.on(SIGTERM, ...)注册信号处理器在收到信号后调用server.close()。2.2 为什么必须保存app.listen()的返回值app.listen()并不返回 Express 的app对象而是返回 Node.js 的http.Server实例。这一行为在 Express 5.x API 文档 中有明确说明app.listen()返回一个http.Server对象且对于 HTTP 场景它只是以下逻辑的便捷封装app.listen function () { const server http.createServer(this); return server.listen.apply(server, arguments); };也就是说app本质上是一个 JavaScript 函数Function被作为回调传给 Node 的http.createServer()。因此server.close()真正调用的是 Node 的http.Server.close()——它停止接受新连接并等待所有已建立的连接处理完毕后触发回调。这正是优雅关闭中停止接收新请求 完成现有请求两个步骤的底层实现。2.3 参数说明参数类型默认值 / 行为portNumberTCP 端口省略或为0时由操作系统分配一个未使用的随机端口hostString接受连接的主机名backlogNumber挂起连接队列的最大长度pathStringUNIX 套接字路径可替代 host port如app.listen(/tmp/sock)callbackFunction服务器开始监听后调用若触发error事件如EADDRINUSE错误会作为该回调的参数传入实际项目中常见写法为const server app.listen(8080, 0.0.0.0, (error) { if (error) { throw error; // 例如 EADDRINUSE } console.log(Listening on ${JSON.stringify(server.address())}); });三、从最小实现到生产级优雅关闭官方示例演示了核心机制但真实生产环境通常需要处理三件额外的事多个信号、资源清理、超时兜底。3.1 同时监听 SIGTERM 与 SIGINTSIGTERM是进程管理器systemd、Kubernetes、Docker 等的标准终止信号而在终端里按CtrlC发送的是SIGINT。两者都应纳入优雅关闭流程const server app.listen(port); function shutdown(signal) { debug(${signal} signal received: closing HTTP server); server.close(() { debug(HTTP server closed); process.exit(0); }); } process.on(SIGTERM, () shutdown(SIGTERM)); process.on(SIGINT, () shutdown(SIGINT));3.2 在server.close()回调中清理资源文档强调收到信号后应释放已使用的资源包括数据库连接和文件锁。常见的清理项包括数据库连接池调用mongoose.disconnect()、pool.end()等文件锁释放proper-lockfile等锁消息队列订阅关闭 Kafka / RabbitMQ 消费者定时器与后台任务clearInterval/clearTimeout。一个综合示例const server app.listen(port); process.on(SIGTERM, async () { debug(SIGTERM signal received: closing HTTP server); // 1. 停止接收新连接等待在途请求完成 server.close(async () { // 2. 清理外部资源 await db.pool.end(); // 关闭数据库连接池 await releaseFileLocks(); // 释放文件锁 debug(HTTP server closed and resources cleaned); process.exit(0); }); });3.3 超时兜底防止优雅关闭卡死server.close()会一直等待所有连接关闭。若存在长连接如 WebSocket、Keep-Alive 挂起请求进程可能迟迟无法退出最终被管理器强杀。生产方案通常增加一个超时定时器宽限期如 10 秒后仍未退出则强制process.exit(1)const server app.listen(port); const SHUTDOWN_TIMEOUT 10_000; // 10 秒宽限期 function shutdown(signal) { debug(${signal} received: closing HTTP server); // 兜底超时后强制退出 const forceExit setTimeout(() { debug(Forcing exit after timeout); process.exit(1); }, SHUTDOWN_TIMEOUT); forceExit.unref(); // 不阻止进程自然退出 server.close(() { debug(HTTP server closed); process.exit(0); }); } process.on(SIGTERM, () shutdown(SIGTERM)); process.on(SIGINT, () shutdown(SIGINT));3.4 与进程管理器、init system 的配合优雅关闭是应用侧的可靠性措施它依赖进程侧的管理器。官方文档 生产最佳实践性能与可靠性 给出了配套建议使用进程管理器如 PM2应用崩溃时自动重启并提供运行时性能洞察、集群模式等能力使用 init system如 systemd系统重启时自动拉起服务。systemd 单元文件中可通过Restartalways实现崩溃自愈并可用TimeoutStopSec控制向应用发送SIGTERM后等待退出的宽限期集群部署cluster每个工作进程独立崩溃、互不影响配合cluster.fork()在 worker 崩溃时重建进程。优雅关闭正是这些外部保障与应用内部协作的关键接口管理器负责发信号应用负责把信号转化为平滑下线。四、健康检查Health Checks让负载均衡器看懂你的应用4.1 原理负载均衡器如何决策负载均衡器Load Balancer通过健康检查判断某个应用实例是否健康、能否接收请求。只有通过健康检查的实例才会被纳入流量转发未通过的实例会被临时摘除从而避免把请求打到已崩溃或正在下线的实例上。官方文档以 Kubernetes 为例指出其提供两种健康检查探针二者职责不同探针作用判定后的动作liveness存活探针判断容器是否还活着失败时重启容器readiness就绪探针判断容器是否准备好接收流量Pod 未就绪时将其从 Service 的负载均衡器中移除4.2 实现健康检查端点在 Express 中健康检查通常实现为两个简单的路由const express require(express); const app express(); // 存活检查进程在、HTTP 能响应即视为活着 app.get(/healthz, (req, res) { res.status(200).send(OK); }); // 就绪检查依赖资源DB、Redis可用才视为就绪 app.get(/readyz, async (req, res) { try { await db.ping(); // 探测数据库连通性 await redisClient.ping(); // 探测缓存连通性 res.status(200).send(READY); } catch (err) { res.status(503).send(NOT READY); // 依赖不可用 → 从负载均衡器摘除 } });要点/healthzliveness应保持轻量只确认进程存活即可不应包含对外部依赖的探测否则一次数据库抖动就会导致容器被反复重启/readyzreadiness应探测关键依赖数据库、缓存、消息队列等不可用时返回503让负载均衡器摘除该实例待恢复后再自动接回。4.3 Kubernetes 探针配置示例apiVersion: apps/v1 kind: Deployment spec: template: spec: containers: - name: express-app image: my-app:1.0.0 ports: - containerPort: 3000 livenessProbe: httpGet: path: /healthz port: 3000 initialDelaySeconds: 3 periodSeconds: 10 readinessProbe: httpGet: path: /readyz port: 3000 initialDelaySeconds: 3 periodSeconds: 54.4 健康检查与优雅关闭的联动零中断滚动发布这是两者组合起来最有价值的一个场景。要让滚动部署rolling update做到请求零丢失需要让下线顺序与探针状态配合Pod 收到SIGTERM前Kubernetes 会先将其从 Endpoints 摘除因为 readiness 探针在终止流程中会自动失效此时负载均衡器不再向该实例转发新流量应用收到SIGTERM进入优雅关闭流程——server.close()停止接受新连接同时等待在途请求完成连接排空完成进程退出旧 Pod 消失新 Pod 已就绪整个过程对客户端几乎无感知。因此健康检查 优雅关闭是一套完整的可靠性闭环健康检查解决实例不可用时如何摘除优雅关闭解决实例下线时如何不中断在途请求。五、小结能力核心 API关键行为仓库依据优雅关闭process.on(SIGTERM)server.close()停接新请求 → 等在途请求 → 清理资源 → 退出API 文档 app.listen 章节存活检查/healthz liveness 探针失败 → 重启容器官方健康检查文档就绪检查/readyz readiness 探针失败 → 摘除出负载均衡器同上进程保障进程管理器 / init system / cluster崩溃重启、系统重启自愈性能与可靠性最佳实践本页面在 expressjs.com 中隶属于Advanced 进阶导航分组见 docs.ts 菜单配置与性能、安全两篇生产实践并列是 Express 应用走向生产环境前必须补齐的最后一块拼图。实践建议先在本地用CtrlCSIGINT验证优雅关闭日志再在 Kubernetes 中用kubectl rollout restart观察滚动发布期间的健康检查摘除与连接排空行为逐步将这套机制打磨为部署流程的标准组成部分。赞分享文档教程技术博客【免费下载链接】expressjs.comThe Express.js Website项目地址https://gitcode.com/gh_mirrors/ex/expressjs.com点击查看免费下载相关推荐让AI写出你团队风格的代码Copilot for Xcode 自定义指令实战指南让AI写出你团队风格的代码Copilot for Xcode 自定义指令实战指南 用AI生成代码时命名风格与项目不一致、错误处理各写各的团队沉淀的规范在每文档教程技术博客SDRPlusPlus 解码 GSM-R 铁路信号从 885 MHz 扫描到 NFM 解调的完整链路SDRPlusPlus 解码 GSM R 铁路信号从 885 MHz 扫描到 NFM 解调的完整链路 用 SDRPlusPlus 做铁路无线通信接收你能独立文档教程技术博客Mumble 主题系统完全指南QSS 样式、图标映射与 .qrc 资源机制深度解析Mumble 主题系统完全指南QSS 样式、图标映射与 .qrc 资源机制深度解析 Mumble 作为开源低延迟语音聊天软件其客户端界面由一套完整的主题文档教程技术博客上一篇程式設計師魚皮 2025 AI 工具箱推薦用得最多的 Top 20 AI 產品與實戰搭配方案下一篇Collection Pipeline 设计模式实战用 Java Stream API 构建声明式数据处理管道创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考