Child Process in node js

Understanding Child Processes in Node JS

Featured, Node JS

Yes we know that node js is single threaded and non blocking, But as the workload increases single thread and single process on a CPU is not enough. So we have landed on this post: Understanding Child Processes in Node JS

But not to worry node js provide us inbuilt module for creating child process so that you can share load between processes.

The child_process module provide us control to make a communication between processes using inbuilt messaging system.

There are 4 different methods of child_process

  1. exec
  2. execFile
  3. spawn
  4. fork

All of these are asynchronous. When we call these methods it will return an object which is an instance of the ChildProcess class.

Lets understand these methods in details:

exec

exec spawns (or you can say create) a new shell and run the given command in that shell. It returns the buffered output . When the child process completed, it calls the callback.

const { exec } = require("child_process");

exec("ls -la", (error, stdout, stderr) => {
    if (error) {
        console.log(`error: ${error.message}`);
        return;
    }
    if (stderr) {
        console.log(`stderr: ${stderr}`);
        return;
    }
    console.log(`stdout: ${stdout}`);
});

Unlike spawn and execFile we can pass multiple commands in exec like we pass in command line using pipe.

exec should be used when we need to utilize shell functionality such as pipe, redirects, background.

execFile

execFile functions is similar to exec except it does not spawn shell by default. It executes the given file or command and gives the buffered output to the callback.


const execFile = require('child_process').execFile;
execFile('node', ['--version'], (error, stdout, stderr) => {
    if (error) {
        console.error('stderr', stderr);
        throw error;
    }
    console.log('stdout', stdout);
});

The callback contains error, stdout and stderr.

Spawn

The spawn method spawns a new process with the given command and returns streaming output.

Spawn returns a stream based object and its great for handling application which returns large amount of data.

const { spawn } = require('child_process');

function runSpawnProcess(cmd, callback) {
    var command = spawn(cmd);
    var result = '';
    command.stdout.on('data', data => {
        result += data.toString();
    });
    command.stderr.on('data', data => {
        return callback(err);
    })
    command.on('close', (code) => {
        return callback(null, result);
    });

    command.on('exit', code => {
        console.log(`child process exited with code ${code}`);
    })
}

runSpawnProcess("ls", (err, result) => {
    if (err)
        console.log(err);

    console.log(result);
});
spawn doesn’t create a shell to execute the command while exec does create a shell. You can force spawn to create a shell using shell: true option.

fork

The child process fork method is a special case of spawn method. In child_process.fork() a communication channel is created between parent and child process to communicate with each other.

The fork method creates an IPC channel allow message to pass between node process.

forkParent.js

const { fork } = require('child_process');

function runForkMethod() {

    const forkProcess = fork("./fork.js");
    let count = 0;

    forkProcess.on('message', (msg) => {
        console.log(`PARENT: message from child process is ${msg}`);

        let customMsg = "this message is from parent";

        forkProcess.send(customMsg);
    });

    forkProcess.on('exit', (code) => {
        console.log(`child_process exited with code ${code}`);
    });
}

runForkMethod()

forkChild.js

let count = Math.floor(Math.random() * 1000);

process.on('message', (msg) => {
    console.log("CHILD: message received from parent process", msg);

    count = parseInt(msg) + 1;

    if (count <= 100)
        process.send(" this is inside process child " + count);
    else
        process.exit(1);
});

console.log(" this is outside process child " + count);
process.send(" sending count from outside process " + count);

In the parent file we fork childFork.js and then we listen to message event. The message event is emitted when child process use process.send.

instead of doing the long operation in the main process event loop, we can fork the single file and use the messages interface to communicate messages between the server and the forked process.

In you have any suggestions to improve this post and have any feedback. Please share it in comments.

References :

https://dzone.com/articles/understanding-execfile-spawn-exec-and-fork-in-node

Leave a Reply