In this lesson, you will learn how to prevent cascading failures by tripping a circuit breaker when your external API calls exceed acceptable latency or error thresholds.
The Problem: Cascading Failures
When your Node.js application relies on a third-party service, a slowdown or outage in that service can be catastrophic. If you continue sending requests to a failing service, your event loop can become clogged with pending promises. This consumes memory and prevents your app from serving other traffic, effectively turning a partial failure into a complete system crash.
The Solution: The Circuit Breaker
A Circuit Breaker acts as an intelligent proxy between your application and the external dependency. It exists in one of three states:
- Closed: Requests flow through normally. The breaker monitors the error rate.
- Open: The external service is deemed "unhealthy." The breaker immediately rejects all requests to the service without even trying to call it, allowing the remote service time to recover.
- Half-Open: After a cooldown period, the breaker allows a single "test" request through. If it succeeds, the circuit closes; if it fails, it returns to the Open state.
Implementation Logic
You don't need a complex library to understand the pattern. You simply wrap your API call logic in a state-checker:
let state = 'CLOSED';
let failureCount = 0;
const THRESHOLD = 5;
async function callExternalService(params) {
if (state === 'OPEN') {
throw new Error('Circuit is open: External service unavailable');
}
try {
const response = await fetch('https://api.example.com/data', { signal: AbortSignal.timeout(2000) });
failureCount = 0; // Reset on success
return response.json();
} catch (err) {
failureCount++;
if (failureCount >= THRESHOLD) {
state = 'OPEN';
// Trigger a timer to transition back to HALF-OPEN after 30s
setTimeout(() => state = 'HALF-OPEN', 30000);
}
throw err;
}
}
By failing fast, you stop wasting resources on a downstream system that is already struggling. This protects your own process, maintains your system's overall stability, and provides a clear mechanism to fail gracefully rather than hanging indefinitely.
Key Takeaway: A Circuit Breaker protects your application from the "slow death" of waiting for failing dependencies by proactively blocking requests once a threshold of failure is met.