Docker 停止容器时,先给主进程发 SIGTERM,默认等 10 秒,进程还没退出就发 SIGKILL 强制结束。服务如果不处理 SIGTERM,正在处理的请求会被直接切断,数据库事务也可能停在一半。
JavaScript
const server = app.listen(3000);
function shutdown(signal) {
console.log(`${signal} received, closing`);
// 停止接收新连接,等进行中的请求处理完
server.close(async () => {
await db.end(); // 关闭数据库连接池
await redis.quit();
process.exit(0);
});
// 兜底:超过 8 秒强制退出,赶在 SIGKILL 之前
setTimeout(() => process.exit(1), 8000).unref();
}
process.on("SIGTERM", () => shutdown("SIGTERM"));
process.on("SIGINT", () => shutdown("SIGINT"));常见的坑
- 容器入口写成
npm start时,信号先到 npm,不一定能转发给 node 进程。Dockerfile 里直接写CMD ["node", "dist/main.js"]。 - 进程作为容器里的 1 号进程时,没有默认的信号处理,不监听 SIGTERM 就会被忽略,只能等 10 秒后被强杀。要么自己监听,要么用
docker run --init。 server.close()只是不再接收新连接,保持连接(keep-alive)的空闲连接会拖住关闭。Node 18.2 起可以再调用server.closeIdleConnections()。- NestJS 要先调用
app.enableShutdownHooks(),onModuleDestroy、beforeApplicationShutdown这些钩子才会在收到信号时执行。