Search code examples
node.jsforkchild-process

Node.js - process.exit() vs childProcess.kill()


I have a node application that runs long running tasks so whenever a task runs a child process is forked to run the task. The code creates a fork for the task to be run and sends a message to the child process to start.

Originally, when the task was complete, I was sending a message back to the parent process and the parent process would call .kill() on the child process. I noticed in my activity monitor that the node processes weren't being removed. All the child processes were hanging around. So, instead of sending a message to the parent and calling .kill(), I called process.exit() in the child process code once the task was complete.

The second approach seems to work fine and I see the node processes being removed from the activity monitor but I'm wondering if there is a downside to this approach that I don't know about. Is one method better than the other? What's the difference between the 2 methods?

My code looks like this for the messaging approach.

//Parent process
    const forked = fork('./app/jobs/onlineConcurrency.js');
    forked.send({clientId: clientData.clientId, 
            schoolYear: schoolYear
        });
    forked.on("message", (msg) => {
        console.log("message", msg);
        forked.kill();
    });

//child Process 
process.on('message', (data) => {
    console.log("Message recieved");
    onlineConcurrencyJob(data.clientId, data.schoolYear, function() {
        console.log("Killing process");
        process.send("done");
    });
})

The code looks like this for the child process when just exiting

//child Process 
process.on('message', (data) => {
    console.log("Message received");
    onlineConcurrencyJob(data.clientId, data.schoolYear, function() {
        console.log("Killing process");
        process.exit();
    });
})

Solution

  • kill sends a signal to the child process. Without an argument, it sends a SIGTERM (where TERM is short for "termination"), which typically, as the name suggests, terminates the process.

    However, sending a signal like that is a forced method of stopping a process. If the process is performing tasks like writing to a file, and it receives a termination signal, it might cause file corruption because the process doesn't get a chance to write all data to the file, and close it (there are mitigations for this, like installing a signal handler that can be used to "catch" signals and ignore them, or finish all tasks before exiting, but this requires explicit code to be added to the child process).

    Whereas with process.exit(), the process exits itself. And typically, it does so at a point where it knows that there are no more pending tasks, so it can exit cleanly. This is generally speaking the best way to stop a (child) process.

    As for why the processes aren't being removed, I'm not sure. It could be that the parent process isn't cleaning up the resources for the child processes, but I would expect that to happen automatically (I don't even think you can perform so-called "child reaping" explicitly in Node.js).