如何防止 Node.js 12 工作线程立即终止?

8

我有一个运行Express服务器和工作线程的Node.js应用程序,该线程定期执行某些操作。

当停止服务器时,我需要清理工作线程在启动时打开的与外部系统的连接。

我尝试为SIGTERM和SIGINT信号在进程上添加处理程序,但这并不起作用。当父进程接收到SIGINT或SIGTERM时,工作线程中的处理函数不会被调用,它立即以退出码1退出,尽管父进程也有这些信号的处理程序,且会被调用。

以下是一个简单的代码示例来重现这个问题:

start.js

const http = require("http");
const express = require("express");
const path = require("path");
const { Worker } = require("worker_threads");

let myWorker = null;

process.on("SIGTERM", stop);
process.on("SIGINT", stop);

const app = express();
const server = http.Server(app);

myWorker = new Worker(path.join(__dirname, "./worker.js"));

myWorker.on("exit", code => console.info(`Worker exited with code ${code}`));

server.listen(3000);

function stop() {
  console.log("Main process: stop()");
  process.exit(0);
}

worker.js

process.on("SIGTERM", stop);
process.on("SIGINT", stop);

setInterval(() => console.log("beep"), 1000);

function stop() {
  console.log("Worker process: stop()");
  process.exit(0);
}

当我启动soWorker.js时,如果我通过CTRL+C中断进程,控制台上会输出以下内容:

╰─➤  node start.js
beep
beep
beep
^CMain process: stop()
Worker exited with code 1

我希望发生的结果是这样的:

╰─➤  node start.js
beep
beep
beep
^CMain process: stop()
Worker process: stop()
Worker exited with code 0

我希望能够调用工作线程中的 stop 函数,以便我可以使用它来关闭与外部系统的连接,并使工作线程进程以返回代码 0 的方式正常退出。

然而,工作线程退出时返回代码 1,这是停止工作线程时的默认值,详情请看

我的问题是:

当主进程终止时,我如何在工作线程中执行清理代码?

上述方法是否正确?

2个回答

7

我这里的建议仅供参考,但我认为这会让你走上正确的轨道:

在 start.js 中添加

process.on('SIGTERM', cleanup);
process.on('SIGINT', cleanup);
myWorker.once('exit', stop);

function cleanup() {
  myWorker.postMessage('cleanup');
}

worker.js

const { parentPort } = require('worker_threads');

parentPort.on('message', (value) => {
  if (value === 'cleanup') {
    cleanup();
    //then process.exit(0);
  }
});


当然,这并不能处理“哦,糟糕,一切都坏了OMG”的情况,但这应该允许您拦截SIGTERM和SIGINT,调用您的工作程序以优雅地关闭,一旦完成,优雅地关闭主要应用程序。 - EddieDean
嗨,Eddie,谢谢你的回答,赏金到期前我会仔细审查它,我现在非常忙,请耐心等待。 - Patrick Hund
我已经尝试过了,它可以正常工作 - 感谢您的帮助! - Patrick Hund

2
以下解决方案应该有效:
  • 在工作线程中订阅主线程的message事件
  • 在主线程中订阅SIGTERM(或其他)
  • 当你在主线程中捕获信号时,向工作线程发送一条消息,请求其清理并退出。**不要立即从主线程退出**。
  • 在主线程中等待工作线程停止,通过订阅exit事件实现
  • 当工作线程停止时,从主线程退出

嗨,Vikash,谢谢你的回答,赏金到期之前我会仔细审查它,我现在非常忙,请耐心等待。 - Patrick Hund
我决定接受Eddie的答案,因为它包含了代码示例。 - Patrick Hund

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接