Circuit breaker pattern for external API dependencies
Why it matters
When an external API — payment gateway, SMS provider, identity service — starts returning errors, repeated synchronous retries amplify load on an already-struggling service and cascade failures throughout your application. CWE-703 (improper check for exceptional conditions) applies to this failure mode. ISO 25010 reliability.fault-tolerance requires the system to degrade gracefully under component failures; a missing circuit breaker means one downstream outage can freeze all request-handling threads or queue workers indefinitely, taking down your entire service.
Severity rationale
Medium because without circuit-breaking, a single downstream API failure causes cascading thread exhaustion or queue saturation across the entire application.
Remediation
Use the opossum library for Node.js or implement a minimal hand-rolled breaker for fetch-based calls. The breaker must track failure rate and reject calls when the circuit is open.
// lib/circuit-breaker.ts
import CircuitBreaker from 'opossum'
export function createBreaker<T>(fn: (...args: unknown[]) => Promise<T>) {
return new CircuitBreaker(fn, {
timeout: 5000, // fail after 5s
errorThresholdPercentage: 50, // open at 50% failure rate
resetTimeout: 30000, // retry after 30s
})
}
// Usage:
const breaker = createBreaker(callPaymentAPI)
const result = await breaker.fire(payload)
Wrap the three highest-traffic external integrations first: payment, auth, and any real-time data feed.
Detection
-
ID:
circuit-breaker-pattern -
Severity:
medium -
What to look for: Count all external service integrations (APIs, databases, third-party services). Enumerate which implement circuit breaker or fallback patterns vs. which fail directly on service unavailability. Search for circuit breaker implementation or library (opossum, circuitbreaker, or hand-rolled logic). Look for a pattern that tracks error rates and fails fast when a threshold is exceeded, preventing cascading failures when an external API is down.
-
Pass criteria: A circuit breaker is implemented for external API dependencies that opens when error rate exceeds a threshold and prevents cascading failures. At least 50% of external service integrations should implement circuit breaker or fallback patterns.
-
Fail criteria: No circuit breaker pattern found; all API calls are retried indefinitely without failure detection.
-
Skip (N/A) when: The application has no external API dependencies.
-
Cross-reference: For retry logic, see
retry-logic-backoff. For graceful API failure, seegraceful-api-failure. -
Detail on fail:
"No circuit breaker implemented. Failed API calls will retry indefinitely, causing slow cascading failures"or"Circuit breaker exists for payment API but not for user service API" -
Remediation: Implement a circuit breaker using a library or manually:
// lib/circuit-breaker.ts — circuit breaker pattern class CircuitBreaker { constructor(private fn: Function, private threshold = 5, private timeout = 30000) {} }// lib/circuitBreaker.ts interface CircuitBreakerState { state: 'closed' | 'open' | 'half-open' failureCount: number lastFailureTime: number } class CircuitBreaker { private state: CircuitBreakerState = { state: 'closed', failureCount: 0, lastFailureTime: 0, } async call<T>(fn: () => Promise<T>, timeout = 5000): Promise<T> { if (this.state.state === 'open') { if (Date.now() - this.state.lastFailureTime > 30000) { this.state.state = 'half-open' } else { throw new Error('Circuit breaker is open') } } try { const result = await Promise.race([ fn(), new Promise((_, reject) => setTimeout(() => reject(new Error('Timeout')), timeout) ), ]) this.reset() return result as T } catch (error) { this.recordFailure() throw error } } private reset() { this.state.failureCount = 0 this.state.state = 'closed' } private recordFailure() { this.state.failureCount++ this.state.lastFailureTime = Date.now() if (this.state.failureCount >= 5) { this.state.state = 'open' } } }
External references
- cwe · CWE-703 — Improper Check or Handling of Exceptional Conditions
- iso-25010:2011 · reliability.fault-tolerance
Taxons
History
- 2026-04-18·v1.0.0·Initial import from error-resilience·automated