patterntypescriptMajor
Circuit breaker with opossum: prevent cascading failures to a slow downstream
Viewed 0 times
opossum ^8.x
circuit breakeropossumpollyresiliencecascading failurefallbacktimeouthalf-open
Error Messages
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.