【发布时间】:2020-08-08 14:17:59
【问题描述】:
我正在为节点 API 实现正常关闭。通常,在开发过程中,这个过程是使用常见的start 脚本开始的,但我注意到这会导致一些令人讨厌的行为,我很惊讶在我作为节点开发人员的 3 年左右之前从未真正注意到过这些行为。
要在开发期间开始关闭,我们只需在 bash 终端中按 ctrl+C,这当然会导致将 SIGINT 发送到 npm 进程及其所有子进程。我可以使用process.on 处理程序来捕获这一点,从那里开始正常关闭——关闭新请求,等待现有请求完成,然后终止数据库连接,所有这些都是好事。
但是,如果开发人员再次按 ctrl+C,npm 的行为会有所不同。它似乎正在向 sh 进程发送一个 SIGTERM,它首先用于调用我的 start 脚本。这会导致sh 进程打印出Terminated 并退出,将终端的控制权返回给用户,而无需等待节点进程退出。
这真的很烦人,因为它给人的印象是节点进程已停止,但当然没有。它会一直持续到关机完成,或者被 SIGKILL 或 SIGQUIT 之类的东西强行杀死。如果它碰巧将任何内容打印到控制台,它将直接在开发人员现在可能在该终端中运行的任何其他内容的中间执行。
举个简单的例子,试试这个:
package.json:
{
"private": true,
"scripts": {
"start": "node index.js"
}
}
index.js:
async function waitForever() {
while(true) {
console.log('waiting...');
await new Promise((resolve) => {
setTimeout(resolve, 5000);
});
}
}
process.on('SIGINT', () => {
console.log('SIGINT recieved');
});
process.on('SIGTERM', () => {
console.log('SIGTERM recieved');
})
waitForever();
在终端中运行npm start,然后按一次 ctrl+c。您会看到信号通过节点,但它当然不会退出。现在,再做一次。您会看到信号再次通过,但随后您会立即看到“已终止”,然后是您的 shell 提示符。在您找到节点进程的进程 ID 并使用 kill -9 将其终止之前,您将每五秒看到 waiting... 消息。
我对这个例子做了更多的摆弄,看起来 npm 完全对此负责。如果您将kill -2 直接发送到 npm 进程两次,则会终止 shell 进程,而节点进程永远不会收到 SIGINT。
所以我有两个主要问题:
这到底是怎么回事?我是否遗漏了有关我的 shell 如何工作的一些信息,或者这是 npm run-script 内置的某种功能?如果是这样,我在哪里可以找到有关此的信息?
npm help run-script对此一无所知。我知道
start脚本在这样的项目中很常见,所以似乎其他人应该遇到这个问题。人们通常如何处理它?我用谷歌搜索了一堆,很难找到一个明确的答案。
当然,这没什么大不了的。启动脚本只是为了确保在启动之前运行 TS 编译很方便。我可以让开发人员在构建后直接在他们的 shell 中运行构建的应用程序,或者编写一个脚本来执行构建并在 npm 脚本之外启动。但最好不必这样做。
我真的很困惑,希望能得到一些帮助。谢谢!
【问题讨论】: