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?

2 Answers 2

7
+100

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

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.
    – EddieDean
    Oct 18, 2019 at 18:05
  • 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 😀 Oct 21, 2019 at 7:06
  • 👍🏻 I've tried it, it works – thank you for your help! Oct 23, 2019 at 9:05
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.
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 😀 Oct 21, 2019 at 7:06
  • I've decided to accept Eddie's answer because it contains code examples. Oct 23, 2019 at 9:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.