Deep Tech Point
first stop in your tech adventure

How to spawn and kill process in Node.js

January 16, 2023 | Javascript

If you are trying to execute the command line program from the Node.js application or to run a node.js application that creates a sub-process you should look into spawn function. Lets explore the details about how to spawn and kill sub-process in Node.js.

Node.js child_process module

Node.js supports modules, it’s core feature. A module is a reusable piece of code. A module may be an independent file, a function, or an object. JavaScript programs can be organized into modules. Modules can be grouped into packages. A package is a collection of modules that can be used as a whole with less work. The module system in JavaScript is designed to encourage developers to create reusable modules of code. When a module in Node.js is executed, the module executes on the context of the program that calls it.

A module can be loaded by using ‘require’ statement. In Node.js, the main process is single threaded. For this reason, we must use the asynchronous process to run modules. The main process does not return a value to indicate the end of process. If we want to know the end of process, we must use the process.exit() method.

Node uses the child_process module to spawn sub-processes which could be other application or shell commands. The spawn function is basically like a bash command line interface (CLI) so that’s the basic idea.

The spawn method

The spawn method in Node.js is used to launch a process. It can be used to execute a command-line executable or a binary. You can use the spawn method from the child_process module to fork a child process with the same Node.js event loop as that of the parent process. Although spawn is not the only way to forking in Node.js, it is the most intuitive. In Node.js, the event loop is asynchronous, but usually the parent process does not wait for its child processes to finish and instead continues with its own code. The spawn function provides a way to create a child process within the Node.js event loop.

To summarize, if you are executing a Node script, the Node.js spawn method will look like this:

var spawn = require('child_process').spawn;

var worker = spawn('node', ['/path/to/my/script.js'], {
    cwd: '/path/to/my/data/'
});

worker.stdout.on('data', function (data) {
    console.log(data);
});

worker.stderr.on('data', (data) => {
    console.error('error: ' + data);
});

worker.on('close', function (code) {
    console.log('Worker process exited with code' + code);
});

The spawn function takes three arguments: a string representing the path to the executable, a list of the program arguments, an optional object used to specify additional options. It returns an object which is a spawn child process.

The child process object has stream properties like stdin, stdout, strerr, stdio. The child process has numerous events you can handle such as close, disconnect, error, exit, spawn, message. The parent process and the child process communicate through messages. These messages are either passed to child process as an argument by the parent process or directly executed in the child process. These messages are nothing but events. Most of the child processes are event loop based and execute these messages in order and wait for the next message to proceed.

The kill method

On non-Windows platforms the child process might not be killed when the main process exits regardless of detached option flag is set to true or false.
This means it’s good practice to kill the child process (sub-process) before main process exits. Alternatively, you should call unref method so the main process event loop won’t include the child in its reference count. This allows the parent process to exit independently of the child process.

Lets see how to kill a child process:

var spawn = require('child_process').spawn;

var worker = spawn('node', ['/path/to/my/script.js'], {
    cwd: '/path/to/my/data/'
});

process.on("exit", function () {
    // if you don't provide argument to kill method the process will be sent the 'SIGTERM' signal
    worker.kill();
});

// handle ctrl+C interrupt
process.on('SIGINT', function() {
  console.log("Caught interrupt signal");
  worker.kill();
});

On the other hand if you want to ‘deatach’ child process of the main process:

var spawn = require('child_process').spawn;

var worker = spawn('node', ['/path/to/my/script.js'], {
    cwd: '/path/to/my/data/',
    detached: true,
    stdio: 'ignore'
});

worker.unref();

To allow child process to stay running in the background after the parent exits we have to provide it with stdio configuration set to ‘ignore’ parent’s stdio. This means child stdio won’t inherit parent’s stdio which is default behavior of child process.

Final thoughts

To support Node.js on different platforms, many developers use the spawn method from the child_process module to fork a child process. Although spawn is not the only way to forking in Node.js, it is the most intuitive. In Node.js, the event loop is asynchronous, and usually the parent process does not wait for its child processes to finish and instead continues with its own code.