Docker中Sails服务器优雅退出:实现SIGTERM/SIGINT下的Promise逻辑
我来帮你搞定这个Sails服务器优雅退出的问题!核心痛点在于Node.js收到SIGTERM/SIGINT信号后,默认会立刻终止进程,根本等不及你endMe里的异步Promise逻辑执行完成。咱们得调整信号处理的方式,确保异步操作跑完再让进程退出。
解决方案核心思路
要让endMe里的Promise逻辑正常执行,关键是阻止进程立即退出,等所有异步操作(比如数据库写入、Sails服务关闭)完成后,再手动调用process.exit()。
修改后的代码示例
假设你的endMe是包含数据库写入逻辑的异步函数,我们可以这样调整:
const util = require("util"); const setTimeoutPromise = util.promisify(setTimeout); // 将endMe改为async函数,确保异步逻辑能被等待 async function endMe(reason) { console.log(reason); try { // 1. 执行数据库写入:标记当前实例为"下线" await YourInstanceModel.updateOne( { instanceId: process.env.INSTANCE_ID } // 假设用环境变量标识实例 ).set({ status: "offline", offlineAt: new Date() }); // 2. 优雅关闭Sails服务(如果需要) await sails.lower(); console.log("优雅退出完成:数据库已更新,Sails服务已关闭"); } catch (err) { console.error("退出过程中出错:", err); // 出错后必须手动退出,避免进程挂起 process.exit(1); } } // 修改信号处理函数为异步,等待endMe执行完成再退出 process.on("SIGTERM", async () => { await endMe("exiting - sigterm"); process.exit(0); }); process.on("SIGINT", async () => { await endMe("exiting - sigint"); process.exit(0); });
如果你的endMe原本就返回Promise(不是async函数),也可以用链式调用的方式:
process.on("SIGTERM", () => { endMe("exiting - sigterm") .then(() => process.exit(0)) .catch(err => { console.error(err); process.exit(1); }); });
关键注意事项
- 错误处理不能少:如果数据库写入或Sails关闭失败,一定要捕获错误并手动退出进程,否则进程会一直挂着,最后被Docker强制发送
SIGKILL终止,丢失退出逻辑。 - Docker超时配置:Docker默认在发送
SIGTERM后等待10秒,超时会触发SIGKILL。如果你的数据库操作可能超过10秒,需要修改Docker的stop-timeout参数,比如:docker run --stop-timeout 30 your-sails-image - 测试要正确:不要用
docker kill测试(会直接发SIGKILL跳过优雅退出),要用docker stop或者在容器内按Ctrl+C(触发SIGINT)来验证逻辑。 - 确保数据库连接可用:要把数据库写入逻辑放在Sails服务关闭之前,避免连接提前断开导致写入失败。
内容的提问来源于stack exchange,提问作者paul23
相关产品推荐
相关产品推荐

