JAVASCRIPT
Implementing a Circuit Breaker for Resilient API Calls
Enhance API call resilience using the Circuit Breaker pattern to prevent cascading failures by temporarily blocking requests to services experiencing issues.
class CircuitBreaker {
constructor(serviceName, failureThreshold = 3, resetTimeout = 5000) {
this.serviceName = serviceName;
this.failureThreshold = failureThreshold;
this.resetTimeout = resetTimeout;
this.failures = 0;
this.state = 'CLOSED'; // CLOSED, OPEN, HALF-OPEN
this.nextAttempt = Date.now();
}
async fire(apiCall) {
if (this.state === 'OPEN' && this.nextAttempt > Date.now()) {
throw new Error(`Circuit for ${this.serviceName} is OPEN. Not attempting call.`);
}
try {
const result = await apiCall();
this.success();
return result;
} catch (error) {
this.fail();
throw error;
}
}
success() {
this.failures = 0;
this.state = 'CLOSED';
console.log(`Circuit for ${this.serviceName} is CLOSED.`);
}
fail() {
this.failures++;
if (this.failures >= this.failureThreshold) {
this.state = 'OPEN';
this.nextAttempt = Date.now() + this.resetTimeout;
console.error(`Circuit for ${this.serviceName} is OPEN. Next attempt at ${new Date(this.nextAttempt).toLocaleTimeString()}`);
} else {
console.warn(`Circuit for ${this.serviceName}: ${this.failures}/${this.failureThreshold} failures.`);
if (this.state === 'HALF-OPEN') {
this.state = 'CLOSED'; // If it fails in HALF-OPEN, close it again
}
}
if (this.state === 'OPEN' && Date.now() >= this.nextAttempt) {
this.state = 'HALF-OPEN';
console.log(`Circuit for ${this.serviceName} is now HALF-OPEN. Trying a single request.`);
}
}
}
// Example Usage:
const externalAPICall = async () => {
const simulateSuccess = Math.random() > 0.3; // 70% success rate
if (simulateSuccess) {
return Promise.resolve({ data: 'External API data' });
} else {
return Promise.reject(new Error('External API failed!'));
}
};
const myServiceCircuit = new CircuitBreaker('ExternalService', 2, 3000);
async function callExternalService() {
try {
const response = await myServiceCircuit.fire(externalAPICall);
console.log('API call successful:', response);
} catch (error) {
console.error('API call failed or circuit open:', error.message);
}
}
setInterval(callExternalService, 1000); // Attempt every second
How it works: The Circuit Breaker pattern enhances resilience by preventing an application from repeatedly trying to access a failing service. It has three states: `CLOSED` (normal operation), `OPEN` (requests are immediately rejected after failures exceed a threshold), and `HALF-OPEN` (after a timeout, a single test request is allowed; if it succeeds, the circuit closes, otherwise it re-opens). This prevents cascading failures, allows the failing service to recover, and provides immediate feedback to the calling application.