Phase 5 · Advanced Node.js & ArchitectureModule 35~68 min read

Worker Threads & Child Processes

Choose and operate worker threads, child processes, and process pools for CPU work, isolation, external tools, and parallel execution.

What you'll learn

Move CPU-heavy JavaScript to a bounded worker-thread pool and launch external programs through explicit arguments and lifecycle controls. Parallelism helps only when work, communication, and failure are budgeted.

By the end of this lesson, you'll be able to:

  • Choose workers, processes, or ordinary async I/O
  • Build a reusable worker pool
  • Transfer data efficiently
  • Control subprocess input, timeouts, and exit

Core mental model

Node.js becomes easier when you separate the JavaScript language from the runtime and the operating-system capabilities it exposes. Use this table as a decision guide.

ConceptWhat it meansDecision rule
Worker threadA separate JavaScript isolate in one processUse for substantial CPU work, not normal I/O
Child processAn isolated OS process or external executableUse for tools or stronger failure boundaries
PoolA bounded reusable set of executorsAvoid startup cost and unbounded parallelism per request

Professional workflow

Build and verify Node.js programs from the terminal in small, observable steps.

  1. Define the parallel execution boundary boundary: inputs, outputs, invariants, ownership, and expected failures.
  2. Design the data or message contract before choosing implementation details.
  3. Implement the smallest correct path with dependencies passed explicitly.
  4. Add validation, failure translation, cleanup, and concurrency behavior.
  5. Verify the boundary with realistic data and at least one adversarial case.
  6. Measure or observe the behavior before optimizing or extracting abstractions.

Keep the feedback loop short

Run the smallest useful command after every meaningful change. Read the complete error message before editing again, and keep inputs and outputs visible while you learn.

Guided code lab

Run an external tool without a shell

execFile receives arguments separately, caps output, and can be aborted; untrusted text never becomes shell syntax.

thumbnail.js
import { execFile } from 'node:child_process';
import { promisify } from 'node:util';
const runFile = promisify(execFile);

await runFile('ffmpeg', ['-i', inputPath, '-frames:v', '1', outputPath], {
  timeout: 15_000,
  maxBuffer: 1024 * 1024,
  windowsHide: true,
});

Production practice

Contract

Every parallel task defines serializable input/output, maximum concurrency, timeout, cancellation, memory budget, and failure translation.

Verification

Test executor crash, timeout, oversized message/output, queue saturation, cancellation, retries, and clean process shutdown.

Operations

Reuse a bounded pool, track queue time and execution time, recycle unhealthy workers, and isolate temporary files.

Common failure mode

Creating one worker per HTTP request moves overload rather than solving it; startup and memory costs can collapse the process.

Independent workshop

Offload image metadata analysis to a worker pool with safe queue limits.

Your finished workshop must include:

  • CPU/I/O decision note
  • Bounded pool
  • Message contract
  • Timeout/cancellation
  • Crash recovery
  • Saturation metrics

Definition of done

Run the happy path and at least two edge cases, keep responsibilities separated, and add a short README explaining how to run the program.

Recap & quick check

Key takeaways

  • Workers serve CPU work
  • Processes improve isolation
  • Pools bound concurrency
  • Messages have cost
  • Shells expand injection risk

Quick check

1. What work best fits worker_threads?

2. Why pool workers?

3. Why prefer execFile for a known binary?

Next: WebSockets & Real-Time Systems