Можно ли предотвратить выход node.js worker из основного процесса - PullRequest
0 голосов
/ 27 мая 2020

Я использую nodejs 12, и этот вопрос относится к https://nodejs.org/api/worker_threads.html Я знаю, что Workers используют тот же процесс, что и основной JS «поток»; все же мне интересно, есть ли способ предотвратить сбой основного процесса любой ошибкой в ​​рабочем коде.

Я хочу использовать рабочий поток вместо разветвленного процесса, но эта проблема будет блокировщиком.

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

1 Ответ

2 голосов
/ 27 мая 2020

Ошибки в воркере не красят sh основной поток . Причина, по которой ваш основной процесс завершается, заключается в том, что больше нет ожидающих событий для события l oop для обработки после выхода рабочего потока. Это то же самое, что и обычные основные сценарии, такие как:

// 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);

Вы обнаружите, что основной поток продолжает выполняться после того, как ваш рабочий поток выйдет из строя.


Дополнительный ответ

Из вашего комментария видно, что вы хотите, чтобы не продолжал работу основной поток, а чтобы рабочий поток продолжал работать. Это невозможно из-за того, как 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 в основной поток:

рабочий. 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);

индекс. 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);
...