Child Processes and Process Management
Spawning and managing child processes in Node.js
Challenge
Section titled “Challenge”You need to run CPU-intensive operations without blocking the event loop. You also need to run external programs or scripts. How do you manage child processes effectively?
Explanation
Section titled “Explanation”Node.js provides multiple ways to spawn child processes, each with different use cases. Understanding fork, spawn, and exec helps you offload work and run external commands.
Child Process Types
Section titled “Child Process Types”const { spawn, exec, execFile, fork } = require('child_process');
// spawn: Stream large outputconst ls = spawn('ls', ['-lh', './']);ls.stdout.on('data', (data) => { console.log(`stdout: ${data}`);});
// exec: Run shell command (small output)exec('ls -lh', (error, stdout, stderr) => { if (error) console.error(error); console.log(stdout);});
// execFile: Run file directlyexecFile('node', ['script.js'], (error, stdout) => { console.log(stdout);});
// fork: Node.js process with IPCconst child = fork('worker.js');child.send({ message: 'Hello from parent' });Solution: CPU-Intensive Work
Section titled “Solution: CPU-Intensive Work”// worker.js - Child processprocess.on('message', (data) => { // Do CPU-intensive work let result = 0; for (let i = 0; i < data.iterations; i++) { result += Math.sqrt(i); }
// Send result back process.send({ result });});
// main.js - Parent processconst { fork } = require('child_process');
const worker = fork('worker.js');
// Send work to workerworker.send({ iterations: 1000000000 });
// Receive resultworker.on('message', (msg) => { console.log('Result from worker:', msg.result);});
// Parent remains responsiveconsole.log('Doing other work...');Process Communication
Section titled “Process Communication”const { fork } = require('child_process');
// Parent processconst child = fork('child.js');
// Send multiple messageschild.send({ cmd: 'getQuote', id: 1 });child.send({ cmd: 'getQuote', id: 2 });
// Handle messages from childchild.on('message', (msg) => { console.log(`Child response: ${msg.quote}`);});
// Detect child exitchild.on('exit', (code) => { console.log(`Child exited with code ${code}`);});
// --- child.js ---process.on('message', (msg) => { if (msg.cmd === 'getQuote') { process.send({ id: msg.id, quote: 'Life is short' }); }});Clustering for Scalability
Section titled “Clustering for Scalability”const cluster = require('cluster');const http = require('http');const os = require('os');
if (cluster.isMaster) { const numWorkers = os.cpus().length;
console.log(`Master process ${process.pid} spawning workers...`);
// Spawn worker processes for (let i = 0; i < numWorkers; i++) { cluster.fork(); }
// Handle worker exit cluster.on('exit', (worker, code) => { console.log(`Worker ${worker.process.pid} died`); cluster.fork(); // Respawn });} else { // Worker process const server = http.createServer((req, res) => { res.writeHead(200); res.end(`Handled by worker ${process.pid}`); });
server.listen(3000); console.log(`Worker ${process.pid} started`);}Stream Processing with Spawning
Section titled “Stream Processing with Spawning”const { spawn } = require('child_process');const fs = require('fs');
// Use gzip compression via spawned processconst gzip = spawn('gzip', ['-c']);const source = fs.createReadStream('input.txt');const destination = fs.createWriteStream('input.txt.gz');
source .pipe(gzip) .pipe(destination) .on('finish', () => { console.log('Compression complete'); });
// Monitor stderr for errorsgzip.stderr.on('data', (data) => { console.error(`stderr: ${data}`);});Error Handling and Timeouts
Section titled “Error Handling and Timeouts”const { spawn } = require('child_process');
const child = spawn('node', ['slow-script.js']);
const timeout = setTimeout(() => { console.log('Process took too long, killing...'); child.kill('SIGTERM'); // Send termination signal}, 5000);
child.on('exit', (code, signal) => { clearTimeout(timeout); if (signal === 'SIGTERM') { console.log('Process was terminated'); } else { console.log(`Process exited with code ${code}`); }});
child.on('error', (err) => { console.error('Failed to start process:', err);});