Express.js Child Processes
Child processes in Node.js allow you to run separate processes for performing tasks concurrently. This guide covers key concepts, examples, and best practices for using child processes in Express.js applications.
Key Concepts of Child Processes
- Child Process: A separate process that runs concurrently with the main process.
- Fork: A method to create a new Node.js process that shares the same code base as the parent process.
- Exec: A method to execute a shell command from within a Node.js process.
- Spawn: A method to launch a new process with a given command.
- ExecFile: A method to execute a file without a shell.
Using Fork to Create Child Processes
Use the fork
method to create a new Node.js process that shares the same code base as the parent process:
Example: Using Fork
// child.js
process.on('message', (msg) => {
console.log(`Child process received message: ${msg}`);
process.send(`Message from child: ${msg}`);
});
// parent.js
const express = require('express');
const { fork } = require('child_process');
const app = express();
const port = 3000;
app.get('/start-child', (req, res) => {
const child = fork('./child.js');
child.send('Hello, child process');
child.on('message', (msg) => {
res.send(`Child process replied: ${msg}`);
});
});
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}/`);
});
Using Exec to Run Shell Commands
Use the exec
method to run shell commands from within a Node.js process:
Example: Using Exec
// exec-example.js
const express = require('express');
const { exec } = require('child_process');
const app = express();
const port = 3000;
app.get('/exec', (req, res) => {
exec('ls', (error, stdout, stderr) => {
if (error) {
res.status(500).send(`Error: ${error.message}`);
return;
}
if (stderr) {
res.status(500).send(`Stderr: ${stderr}`);
return;
}
res.send(`Stdout: ${stdout}`);
});
});
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}/`);
});
Using Spawn to Launch a New Process
Use the spawn
method to launch a new process with a given command:
Example: Using Spawn
// spawn-example.js
const express = require('express');
const { spawn } = require('child_process');
const app = express();
const port = 3000;
app.get('/spawn', (req, res) => {
const ls = spawn('ls', ['-lh', '/usr']);
let data = '';
ls.stdout.on('data', (chunk) => {
data += chunk;
});
ls.on('close', (code) => {
res.send(`Process exited with code: ${code}\n${data}`);
});
});
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}/`);
});
Using ExecFile to Execute a File
Use the execFile
method to execute a file without a shell:
Example: Using ExecFile
// execfile-example.js
const express = require('express');
const { execFile } = require('child_process');
const app = express();
const port = 3000;
app.get('/execfile', (req, res) => {
execFile('/path/to/executable', (error, stdout, stderr) => {
if (error) {
res.status(500).send(`Error: ${error.message}`);
return;
}
if (stderr) {
res.status(500).send(`Stderr: ${stderr}`);
return;
}
res.send(`Stdout: ${stdout}`);
});
});
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}/`);
});
Communicating with Child Processes
Parent and child processes can communicate using the send
method:
Example: Parent-Child Communication
// child.js
process.on('message', (msg) => {
console.log(`Child process received message: ${msg}`);
process.send(`Message from child: ${msg}`);
});
// parent.js
const express = require('express');
const { fork } = require('child_process');
const app = express();
const port = 3000;
app.get('/start-child', (req, res) => {
const child = fork('./child.js');
child.send('Hello, child process');
child.on('message', (msg) => {
res.send(`Child process replied: ${msg}`);
});
});
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}/`);
});
Best Practices for Using Child Processes
- Limit Resource Usage: Ensure child processes do not consume excessive resources.
- Handle Errors: Always handle errors in child processes to prevent crashes.
- Use Proper Communication: Use the
send
method for proper communication between parent and child processes. - Clean Up Processes: Ensure child processes are properly cleaned up after completion.
- Security: Ensure secure handling of data and commands in child processes to prevent security risks.
Testing Child Processes
Test your child process-based code using frameworks like Mocha, Chai, and Supertest:
Example: Testing Child Processes
// Install Mocha, Chai, and Supertest
// npm install --save-dev mocha chai supertest
// test/child-process.test.js
const chai = require('chai');
const expect = chai.expect;
const request = require('supertest');
const express = require('express');
const { fork } = require('child_process');
const app = express();
app.get('/start-child', (req, res) => {
const child = fork('./child.js');
child.send('Hello, child process');
child.on('message', (msg) => {
res.send(`Child process replied: ${msg}`);
});
});
describe('GET /start-child', () => {
it('should start the child process and receive a reply', (done) => {
request(app)
.get('/start-child')
.expect(200)
.end((err, res) => {
if (err) return done(err);
expect(res.text).to.include('Child process replied:');
done();
});
});
});
// Define test script in package.json
// "scripts": {
// "test": "mocha"
// }
// Run tests with NPM
// npm run test
Key Points
- Child Process: A separate process that runs concurrently with the main process.
- Fork: A method to create a new Node.js process that shares the same code base as the parent process.
- Exec: A method to execute a shell command from within a Node.js process.
- Spawn: A method to launch a new process with a given command.
- ExecFile: A method to execute a file without a shell.
- Follow best practices for using child processes, such as limiting resource usage, handling errors, using proper communication, cleaning up processes, and ensuring security.
Conclusion
Child processes in Node.js allow you to run separate processes for performing tasks concurrently. By understanding and implementing the key concepts, examples, and best practices covered in this guide, you can effectively manage child processes in your Express.js applications. Happy coding!