Maximizing the Power of Child Processes in Node.js: Real-world Examples
Aymen kani|May 26th 2023

Node.js is a popular open-source JavaScript runtime that allows developers to build scalable and high-performance web applications. One of the most powerful features of Node.js is its ability to handle child processes. Child processes allow you to spawn new processes, run shell commands, execute scripts, or even fork multiple processes to handle a heavy workload. In this blog post, we will discuss how to use child processes in Node.js and provide real-world examples of how they can be used to improve the performance and scalability of your application.

Using the Child Process module

The built-in 'child_process' module in Node.js provides several methods for spawning and managing child processes. The most commonly used methods are 'exec', 'spawn', and 'fork'.

'exec' method: This method allows you to run a shell command and capture its output. Here is an example of how to use the 'exec' method to run the 'ls -la' command, which lists the files and directories in the current directory:

javascript

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

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

In this example, the 'exec' function is used to run the 'ls -la' command, and the output of the command is captured in the 'stdout' variable and any error messages are captured in the 'stderr' variable.

'Spawn' method: This method allows you to spawn a new process with a given command. Here is an example of how to use the 'spawn' method to run the 'ls -la' command:

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

const child = spawn('ls', ['-la']);

child.stdout.on('data', (data) => {
  console.log(`stdout: ${data}`);
});

child.stderr.on('data', (data) => {
  console.error(`stderr: ${data}`);
});

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

In this example, the 'spawn' function is used to spawn a new process running the 'ls' command with the '-la' argument. The 'stdout', 'stderr', and 'close' events are used to handle the output and exit status of the child process.

'Fork' method: This method allows you to spawn a new Node.js process and communicate with it using inter-process communication (IPC) mechanisms. Here is an example of how to use the 'fork' method to spawn a new process running the 'child.js' file:

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

const child = fork('child.js');

child.on('message', (message) => {
  console.log(`Received message from child: ${message}`);
});

child.send({ message: 'Hello from the parent!' });

In this example, the 'fork' function is used to spawn a new Node.js process running the 'child.js' file. The 'child' object returned by the 'fork' function can be used to send and receive messages from the child process using 'on' and 'send' methods. In this example, the parent process is sending a message to the child process and it listens for a message from the child process.

Child processes for background tasks

One real-world example of using child processes for background tasks is scheduling regular tasks, such as sending emails or generating reports.

For example, let's say you have a web application that needs to send a weekly newsletter to all registered users. Instead of sending the emails synchronously and blocking the main event loop, you can use a child process to handle the email sending task in the background.

Here's an example of how you could accomplish this using the child_process.fork method:

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

// Fork a child process to handle the email sending task
const child = fork('send-email.js');

// Send a message to the child process to start the email sending task
child.send({ task: 'send-newsletter' });

// Listen for messages from the child process
child.on('message', (message) => {
  console.log(`Background task ${message.task} completed`);
});

And here's an example of what the send-email.js file might look like:

javascript
process.on('message', (message) => {
  if (message.task === 'send-newsletter') {
    // Retrieve the list of registered users from the database
    const users = getUsersFromDatabase();
  
    // Send the weekly newsletter to each user
    users.forEach((user) => {
      sendEmail(user.email, 'Weekly Newsletter', 'Hello, here is this week newsletter');
    });

    // Send a message to the parent process to notify that the task is completed
    process.send({ task: 'send-newsletter' });
  }
});

In this example, the parent process forks a child process to handle the email sending task. The parent process sends a message to the child process to start the task and listens for messages from the child process. The child process receives the message, retrieves the list of registered users from the database, and sends the weekly newsletter to each user using a function called sendEmail that you have to implement. Once the task is completed, the child process sends a message to the parent process to notify that the task is completed.

This way the email sending process is moved to the child process and it won't block the main event loop, allowing the application to continue handling other requests while the emails are being sent in the background.

This is just one example and you can use this concept for other background tasks like sending SMS, generating PDF reports, or scraping web pages.

Hey! check out my Nodejs Course on Udemy

more real world example

  1. Parallel Processing: One of the most common use cases for child processes is to perform parallel processing. By forking multiple child processes, you can take advantage of multiple CPU cores and handle a heavy workload in a more efficient way. For example, you can use the 'fork' method to fork multiple child processes to perform image processing or data analysis tasks.
  2. Running Shell Scripts: Another common use case for child processes is to run shell scripts. You can use the 'exec' method to run shell commands and capture the output, or use the 'spawn' method to run a shell script and handle the output.
  3. Communication with other Services: Child processes can also be used to communicate with other services such as databases, external APIs, or other microservices. For example, you can use child processes to perform tasks such as sending requests to an external API, performing database queries, or communicating with other microservices.

In conclusion, child processes are a powerful feature of Node.js that can be used to improve the performance and scalability of your application. By utilizing child processes, you can perform parallel processing, run shell scripts, handle background tasks, and communicate with other services in a more efficient way. Whether you are a beginner or an experienced developer, understanding how to use child processes in Node.js can greatly enhance your development skills.

Read Next

Node.jsChild ProcessesPerformanceScalability Real-world examples