Leadline Architecture Design

Reliability and concurrency

Circuit breaker behavior at HTTP boundaries and worker threads for CPU-bound work in Node.js and NestJS.

Circuit breaker

The circuit breaker pattern stops calling a dependency that is failing persistently, failing fast instead of tying up threads, sockets, and memory. That protects the service and gives downstream systems time to recover.

States

  1. Closed: traffic flows normally.
  2. Open: failures exceeded a threshold; calls short-circuit without hitting the dependency until a cool-down elapses.
  3. Half-open: a limited probe checks whether the dependency has recovered before closing again.

In NestJS

Implement as a custom interceptor, a dedicated service wrapper, or a battle-tested library—whichever matches your observability and configuration needs. Typical configuration knobs:

  • failure and success thresholds
  • open-state duration before half-open probes
  • which exception types count as failures
  • optional fallback responses for critical routes

Practices: apply at clear integration boundaries; log state transitions; alert when circuits stay open; tune thresholds from real traffic; pair with timeouts and retries for transient faults where appropriate.

Worker threads

Node.js runs JavaScript on a single thread per process; CPU-bound work blocks the event loop and hurts latency for all concurrent requests. Worker threads run isolated V8 instances and communicate via messages, keeping the main thread responsive.

When it fits: heavy computation (cryptography, image processing, large transforms), synchronous libraries that monopolize the CPU, or batch report generation.

Basic shape

A worker file performs the computation; a Nest provider wraps Worker lifecycle (onModuleInit / onModuleDestroy), posts jobs, and exposes results (for example as an Observable or Promise).

Pools: prefer a worker pool (for example Piscina) over creating a new worker per request to amortize startup cost and bound concurrency.

Practices: only offload work that is large enough to justify serialization and thread overhead; use transferable buffers when moving big binary data; terminate or destroy pools on shutdown; use stable paths (import.meta.url or resolved absolute paths) for worker entry files.

When not to use workers: I/O-bound work is usually better served by Node’s async APIs and proper back-pressure—not by extra threads.

This page and links

Loading map…

On this page