可以阻止 node.js 工作人员退出主进程吗

Can one prevent a node.js worker from exiting the main process

我正在使用 nodejs 12,这个问题与 https://nodejs.org/api/worker_threads.html 有关 我知道 Workers 与主 JS 共享相同的进程 "thread";我仍然想知道是否有办法防止工作代码中的任何错误导致主进程崩溃。

我想使用工作线程而不是分叉进程,但这个问题会成为障碍。

worker.js

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

let i = 0;
setInterval(() => {
  parentPort.postMessage({ hello: "world" });
  i++;
  if (i > 5) {
    throw new Error('Hello'); // imagine here some error that hasn't been caught
  }
}, 200);

setInterval(() => {
  parentPort.postMessage({ foo: "bar" });
}, 600);

index.js

const { Worker } = require("worker_threads");
const worker = new Worker("./worker.js");

worker.on("error", (err) => {
  console.error(err);
});

worker.on("exit", () => {
  console.log('Worker exited')
});

worker.on("message", msg => {
  console.log(msg)
});

Output

➜ node index.js
{ hello: 'world' }
{ hello: 'world' }
{ foo: 'bar' }
{ hello: 'world' }
{ hello: 'world' }
{ hello: 'world' }
{ foo: 'bar' }
{ hello: 'world' }
Error: Something happened
    at Timeout._onTimeout (/Users/micael/Desktop/crashing/worker.js:10:11)
    at listOnTimeout (internal/timers.js:549:17)
    at processTimers (internal/timers.js:492:7)
Worker exited

worker 中的错误不会导致主线程崩溃。您的主进程退出的原因是因为一旦工作线程退出,事件循环就没有更多待处理的事件要处理。这与常规主脚本相同,例如:

// index.js
console.log('hello');
// this scripts exits here

如果您 运行 上面的简单脚本,您将看到 node.js 在脚本末尾退出主进程。这是正常行为。

为了证明这一点,请让您的主线程做些其他事情:

// index.js
const { Worker } = require("worker_threads");
const worker = new Worker("./worker.js");

worker.on("error", (err) => {
  console.error(err);
});

worker.on("exit", () => {
  console.log('Worker exited')
});

worker.on("message", msg => {
  console.log(msg)
});

setInterval(() => console.log('main is running'), 500);

你会发现主线程在你的工作线程崩溃后继续运行。


补充回答

从您的评论看来,您想要的不是让主线程继续 运行ning,而是让工作线程继续 运行ning。根据 javascript 处理未捕获错误的方式,这是不可能的:解释器将简单地记录错误并退出。解释器退出将导致线程终止。

如果您希望第二个 setTimeout 在工作线程结束后继续,您需要 运行 它在一个单独的线程中:

worker1.js:

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

let i = 0;
setInterval(() => {
  parentPort.postMessage({ hello: "world" });
  i++;
  if (i > 5) {
    throw new Error('Hello'); // imagine here some error that hasn't been caught
  }
}, 200);

worker2.js:

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

setInterval(() => {
  parentPort.postMessage({ foo: "bar" });
}, 600);

index.js:

const { Worker } = require("worker_threads");
const worker1 = new Worker("./worker.js");
const worker2 = new Worker("./worker.js");

worker1.on("error", (err) => {
  console.error(err);
});

worker1.on("exit", () => {
  console.log('Worker exited')
});

worker1.on("message", msg => {
  console.log(msg)
});

worker2.on("error", (err) => {
  console.error(err);
});

worker2.on("exit", () => {
  console.log('Worker exited')
});

worker2.on("message", msg => {
  console.log(msg)
});

或者你可以运行主线程中的第二个setInterval:

worker.js:

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

let i = 0;
setInterval(() => {
  parentPort.postMessage({ hello: "world" });
  i++;
  if (i > 5) {
    throw new Error('Hello'); // imagine here some error that hasn't been caught
  }
}, 200);

index.js:

const { Worker } = require("worker_threads");
const worker = new Worker("./worker.js");

worker.on("error", (err) => {
  console.error(err);
});

worker.on("exit", () => {
  console.log('Worker exited')
});

worker.on("message", msg => {
  console.log(msg)
});

setInterval(() => {
  parentPort.postMessage({ foo: "bar" });
}, 600);