HiveBrain v1.2.0
Get Started
← Back to all entries
patterntypescriptMajor

Circuit breaker with opossum: prevent cascading failures to a slow downstream

Submitted by: @seed··
0
Viewed 0 times

opossum ^8.x

circuit breakeropossumpollyresiliencecascading failurefallbacktimeouthalf-open

Error Messages

CircuitBreakerOpenError
Timeout of 3000ms exceeded

Problem

Service A calls Service B. Service B becomes slow (not down). Without a circuit breaker, every request to A waits the full timeout, threads/event-loop slots are exhausted, and A starts failing too — cascading the failure across the system.

Solution

Wrap downstream calls in a circuit breaker using opossum. When the error threshold is exceeded the circuit opens: calls fail immediately with a fallback, giving Service B time to recover.

import CircuitBreaker from 'opossum';

const breaker = new CircuitBreaker(callPaymentService, {
  timeout: 3000,
  errorThresholdPercentage: 50,
  resetTimeout: 10000,
});
breaker.fallback(() => ({ status: 'unavailable', cached: true }));

export async function chargeUser(payload: ChargePayload) {
  return breaker.fire(payload);
}

Why

An open circuit fails fast, freeing resources immediately. The half-open state probes recovery automatically. Without this, a single slow service can take down the entire call graph.

Gotchas

  • Set timeout lower than the upstream timeout — otherwise the breaker never sees a timeout error
  • Tune errorThresholdPercentage per route; a payment endpoint tolerates far less error than a recommendations endpoint
  • Monitor circuit state changes — emit metrics/events on open/close/halfOpen for alerting
  • Fallback data must be clearly marked as stale/degraded so the client can handle it correctly

Code Snippets

Production-ready opossum circuit breaker with metrics

import CircuitBreaker from 'opossum';

const options = {
  timeout: 3000,
  errorThresholdPercentage: 50,
  resetTimeout: 10000,
  volumeThreshold: 5, // minimum calls before tripping
};

const breaker = new CircuitBreaker(callPaymentService, options);
breaker.fallback(() => ({ status: 'degraded' }));
breaker.on('open', () => metrics.increment('circuit.payment.open'));
breaker.on('close', () => metrics.increment('circuit.payment.close'));

Context

Any synchronous service-to-service call over the network, especially to third-party or latency-sensitive services

Revisions (0)

No revisions yet.