Bird
Raised Fist0
Node.jsframework~10 mins

Forking workers per CPU core in Node.js - Step-by-Step Execution

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Concept Flow - Forking workers per CPU core
Start Master Process
Get CPU Core Count
For each CPU core
Fork a Worker Process
Workers run tasks in parallel
Master listens for worker exit
If worker exits, fork a new one
End
The master process counts CPU cores, forks one worker per core, and restarts workers if they exit.
Execution Sample
Node.js
import cluster from 'node:cluster';
import os from 'node:os';

if (cluster.isPrimary) {
  const cpuCount = os.cpus().length;
  for (let i = 0; i < cpuCount; i++) {
    cluster.fork();
  }
}
This code forks one worker process per CPU core from the master process.
Execution Table
StepActionValue/ResultNotes
1Check if process is mastercluster.isPrimary = trueMaster process starts
2Get CPU core countcpuCount = 4Assuming 4 cores on machine
3Start loop i=0i=0First iteration
4Fork workerWorker 1 createdWorker process 1 starts
5Increment ii=1Next iteration
6Fork workerWorker 2 createdWorker process 2 starts
7Increment ii=2Next iteration
8Fork workerWorker 3 createdWorker process 3 starts
9Increment ii=3Next iteration
10Fork workerWorker 4 createdWorker process 4 starts
11Increment ii=4Loop ends, i == cpuCount
12Master listens for worker exitIf worker exits, fork new workerEnsures continuous availability
13Workers run tasksParallel processingWorkers handle workload independently
14ExitAll workers runningMaster process waits
💡 Loop ends when i equals cpuCount; all workers forked.
Variable Tracker
VariableStartAfter 1After 2After 3After 4Final
iundefined01234
cpuCountundefined44444
cluster.isPrimaryundefinedtruetruetruetruetrue
Key Moments - 3 Insights
Why do we check if cluster.isPrimary before forking?
Because only the master process should fork workers. Workers should not fork more processes. See execution_table step 1.
What happens if we don't fork one worker per CPU core?
We might not fully use all CPU cores, leading to less efficient processing. The loop in steps 3-11 ensures one worker per core.
Why does the master listen for worker exit and fork new ones?
To keep the system running smoothly by replacing any worker that crashes or exits unexpectedly, as shown in step 12.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution_table, what is the value of 'i' when the third worker is forked?
A2
B3
C1
D4
💡 Hint
Check steps 7 and 8 where i increments and the third worker is created.
At which step does the loop end because i equals cpuCount?
AStep 10
BStep 11
CStep 12
DStep 9
💡 Hint
Look for the step where i becomes 4 and the loop stops.
If the machine has 8 CPU cores, how many times will the loop run?
A4
B6
C8
D1
💡 Hint
Refer to variable_tracker for cpuCount and loop iterations.
Concept Snapshot
Forking workers per CPU core in Node.js:
- Use cluster.isPrimary to check master process
- Get CPU count with os.cpus().length
- Loop from 0 to cpuCount-1
- Fork a worker each iteration
- Master listens for worker exit to restart
- This uses all CPU cores for parallel work
Full Transcript
In Node.js, to use all CPU cores, the master process first checks if it is the primary process using cluster.isPrimary. It then gets the number of CPU cores with os.cpus().length. A loop runs from zero up to one less than the CPU count, and in each loop iteration, the master forks a new worker process. Each worker runs independently to handle tasks in parallel. The master also listens for any worker exiting and forks a new one to keep the system running smoothly. This approach maximizes CPU usage by having one worker per core.

Practice

(1/5)
1. What is the main reason to fork workers equal to the number of CPU cores in a Node.js app?
easy
A. To make the app run slower for debugging purposes
B. To use all CPU cores and improve performance by running tasks in parallel
C. To reduce memory usage by limiting the number of processes
D. To avoid using the cluster module

Solution

  1. Step 1: Understand CPU cores and parallelism

    Each CPU core can run one process at a time, so using all cores means better performance.
  2. Step 2: Role of forking workers

    Forking workers equal to CPU cores lets Node.js run multiple tasks simultaneously, improving speed.
  3. Final Answer:

    To use all CPU cores and improve performance by running tasks in parallel -> Option B
  4. Quick Check:

    Fork workers = use all cores = better performance [OK]
Hint: More workers = more CPU cores used = faster app [OK]
Common Mistakes:
  • Thinking forking reduces memory usage
  • Believing forking slows the app
  • Confusing cluster module usage
2. Which of the following is the correct way to get the number of CPU cores in Node.js for forking workers?
easy
A. const cores = require('os').cpus().length;
B. const cores = require('cluster').cpuCount;
C. const cores = require('os').cpuCount();
D. const cores = require('os').cpus.length;

Solution

  1. Step 1: Check Node.js os module usage

    The os module has a method cpus() that returns an array of CPU core info.
  2. Step 2: Correct syntax to get core count

    Using cpus().length gives the number of CPU cores available.
  3. Final Answer:

    const cores = require('os').cpus().length; -> Option A
  4. Quick Check:

    os.cpus() returns array, length gives core count [OK]
Hint: Use os.cpus().length to count CPU cores [OK]
Common Mistakes:
  • Forgetting parentheses after cpus
  • Using non-existent cpuCount method
  • Trying to get cores from cluster module
3. Given this code snippet, what will be logged when run on a machine with 4 CPU cores?
const cluster = require('cluster');
const os = require('os');

if (cluster.isPrimary) {
  const numCPUs = os.cpus().length;
  console.log(`Primary process is running`);
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }
} else {
  console.log(`Worker ${process.pid} started`);
}
medium
A. Primary process is running Worker 1234 started Worker 1235 started Worker 1236 started Worker 1237 started
B. Primary process is running Worker started Worker started Worker started Worker started
C. Primary process is running Worker 1234 started
D. SyntaxError due to missing cluster setup

Solution

  1. Step 1: Identify primary and worker behavior

    The primary logs once and forks 4 workers (one per CPU core).
  2. Step 2: Each worker logs its own process id

    Each worker logs "Worker [pid] started" with its unique process id.
  3. Final Answer:

    Primary process is running Worker 1234 started Worker 1235 started Worker 1236 started Worker 1237 started -> Option A
  4. Quick Check:

    Primary logs once, 4 workers log with pids [OK]
Hint: Primary logs once; each worker logs with unique pid [OK]
Common Mistakes:
  • Assuming workers log without pid
  • Thinking only one worker starts
  • Confusing primary and worker logs
4. What is wrong with this code snippet that tries to fork workers per CPU core?
const cluster = require('cluster');
const os = require('os');

if (cluster.isPrimary) {
  const numCPUs = os.cpus.length;
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }
} else {
  console.log('Worker started');
}
medium
A. cluster.fork() is not a function
B. No error; code works fine
C. Missing else block for worker process
D. os.cpus.length is undefined; should be os.cpus().length

Solution

  1. Step 1: Check os module usage

    os.cpus is a function, so os.cpus.length is undefined and causes error.
  2. Step 2: Correct usage

    Use os.cpus().length to get the number of CPU cores correctly.
  3. Final Answer:

    os.cpus.length is undefined; should be os.cpus().length -> Option D
  4. Quick Check:

    os.cpus() is function, need parentheses [OK]
Hint: Remember os.cpus() is a function, not a property [OK]
Common Mistakes:
  • Forgetting parentheses on os.cpus()
  • Assuming cluster.fork() is missing
  • Thinking else block is required for syntax
5. You want to create a Node.js server that forks one worker per CPU core and restarts any worker if it crashes. Which code snippet correctly implements this behavior?
hard
A. const cluster = require('cluster'); const http = require('http'); const os = require('os'); if (cluster.isPrimary) { const numCPUs = os.cpus().length; for (let i = 0; i < numCPUs; i++) { cluster.fork(); } } else { http.createServer((req, res) => { res.writeHead(200); res.end('Hello from worker ' + process.pid); }).listen(8000); cluster.on('exit', (worker) => { console.log(`Worker ${worker.process.pid} died`); }); }
B. const cluster = require('cluster'); const http = require('http'); const os = require('os'); if (cluster.isWorker) { const numCPUs = os.cpus().length; for (let i = 0; i < numCPUs; i++) { cluster.fork(); } } else { http.createServer((req, res) => { res.writeHead(200); res.end('Hello from worker ' + process.pid); }).listen(8000); }
C. const cluster = require('cluster'); const http = require('http'); const os = require('os'); if (cluster.isPrimary) { const numCPUs = os.cpus().length; for (let i = 0; i < numCPUs; i++) { cluster.fork(); } cluster.on('exit', (worker) => { console.log(`Worker ${worker.process.pid} died, restarting...`); cluster.fork(); }); } else { http.createServer((req, res) => { res.writeHead(200); res.end('Hello from worker ' + process.pid); }).listen(8000); }
D. const cluster = require('cluster'); const http = require('http'); const os = require('os'); if (cluster.isPrimary) { cluster.fork(); } else { http.createServer((req, res) => { res.writeHead(200); res.end('Hello from worker ' + process.pid); }).listen(8000); }

Solution

  1. Step 1: Fork one worker per CPU core in primary process

    In if (cluster.isPrimary), use const numCPUs = os.cpus().length; for (let i = 0; i < numCPUs; i++) cluster.fork();
  2. Step 2: Restart workers on exit event

    In primary process, cluster.on('exit', (worker) => { console.log(`Worker ${worker.process.pid} died, restarting...`); cluster.fork(); });
  3. Step 3: Worker creates HTTP server

    Workers create the HTTP server listening on port 8000, responding with their pid.
  4. Final Answer:

    forks one worker per CPU core and restarts any worker if it crashes -> Option C
  5. Quick Check:

    Primary forks os.cpus().length + cluster.on('exit', fork()) + workers create HTTP server [OK]
Hint: Use cluster.on('exit') in primary to restart workers [OK]
Common Mistakes:
  • Using cluster.isWorker instead of cluster.isPrimary
  • Not restarting workers on exit
  • Forking workers inside worker process