How to Prevent a Node.js 12 worker Thread from terminating immediately?
Asked Answered
S

2

8

I have a Node.js application running an Express server and a worker thread that does something at regular intervals.

When the server is stopped, I need to clean up a connection to an external system that is opened by the worker thread when it starts.

I tried to add a handler on the process for SIGTERM and SIGINT signals, but this does not work, the handler function in the worker thread is not called, it exits immediately with exit code 1 when the parent process receives a SIGINT or SIGTERM, although the parent process also has a handler for these which does get called.

Here is a simple code example to reproduce the problem:

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

When I start soWorker.js, I get this output on the console when I interrupt the process with CTRL+C:

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

What I expect to happen is this:

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

I expect the stop function in the worker thread to be called, so that I can use it to close the connection to the external system, then gracefully exit the worker thread process with return code 0.

Instead, the worker thread exits with code 1, which is the default when a worker thread is stopped.

My question:

How can I execute some clean-up code in my worker thread when the main process is terminated?

Am I on the right track with the approach described above?

Satirize answered 13/10, 2019 at 16:52 Comment(0)
S
7

I'm mostly spitballin' here, but I think this'll put you on the right track:

add to 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);
  }
});
Shamekashameless answered 18/10, 2019 at 18:3 Comment(3)
Of course this doesn't handle the "oh crap everything is broken OMG" stuff, but this should allow you to intercept the SIGTERM and SIGINT, call your worker to gracefully shutdown, and once that's done, gracefully shutdown the primary application.Shamekashameless
Hi Eddie, thank you for your answer, I will review it before the bounty runs out, I'm really busy a.t.m. so please be patient 😀Satirize
👍🏻 I've tried it, it works – thank you for your help!Satirize
B
2

The following solution should work-

  • Subscribe to main thread message event in the worker thread
  • Subscribe to SIGTERM (or whatever) in the main thread
  • When you catch the signal in the main thread, send a message to the worker thread, requesting it to clean up and exit. ** Do not exit from the main thread yet**.
  • In the main thread wait for worker thread to stop by subscribing to exit event.
  • When worker thread stops, exit from the main thread.
Backcourt answered 20/10, 2019 at 5:24 Comment(2)
Hi Vikash, thank you for your answer, I will review it before the bounty runs out, I'm really busy a.t.m. so please be patient 😀Satirize
I've decided to accept Eddie's answer because it contains code examples.Satirize

© 2022 - 2024 — McMap. All rights reserved.