Circuit Breaker
Pattern de résilience qui protège les applications contre les défaillances en cascade en interrompant automatiquement les appels vers des services défaillants.
Mis à jour le 9 janvier 2026
Le Circuit Breaker est un pattern architectural inspiré des disjoncteurs électriques, conçu pour améliorer la résilience des systèmes distribués. Il surveille les appels vers des services externes et interrompt automatiquement les requêtes lorsqu'un certain seuil d'échecs est atteint, permettant ainsi au système de se stabiliser et évitant la propagation des défaillances à travers l'architecture.
Fondements
- Trois états distincts : Closed (fermé, opérations normales), Open (ouvert, blocage des appels), Half-Open (semi-ouvert, tests de récupération)
- Surveillance continue des taux d'échec et des latences pour détecter les anomalies
- Mécanisme de timeout et de fallback pour gérer gracieusement les défaillances
- Récupération automatique avec phase de test progressive avant rétablissement complet
Avantages
- Prévention des défaillances en cascade dans les architectures microservices
- Réduction du temps de réponse en évitant les appels vers des services indisponibles
- Protection des ressources système (threads, connexions) contre l'épuisement
- Amélioration de l'expérience utilisateur avec des réponses rapides même en cas de panne
- Facilitation du diagnostic avec métriques détaillées sur les échecs et les patterns
- Permettre la récupération automatique sans intervention manuelle
Exemple concret
Voici une implémentation TypeScript d'un Circuit Breaker pour protéger les appels API externes :
enum CircuitState {
CLOSED = 'CLOSED',
OPEN = 'OPEN',
HALF_OPEN = 'HALF_OPEN'
}
interface CircuitBreakerConfig {
failureThreshold: number; // Nombre d'échecs avant ouverture
successThreshold: number; // Succès requis pour fermer
timeout: number; // Temps avant test de récupération (ms)
monitoringPeriod: number; // Fenêtre de surveillance (ms)
}
class CircuitBreaker {
private state: CircuitState = CircuitState.CLOSED;
private failureCount = 0;
private successCount = 0;
private lastFailureTime?: number;
private nextAttempt?: number;
constructor(private config: CircuitBreakerConfig) {}
async execute<T>(operation: () => Promise<T>): Promise<T> {
if (this.state === CircuitState.OPEN) {
if (Date.now() < this.nextAttempt!) {
throw new Error('Circuit breaker is OPEN');
}
this.state = CircuitState.HALF_OPEN;
this.successCount = 0;
}
try {
const result = await operation();
this.onSuccess();
return result;
} catch (error) {
this.onFailure();
throw error;
}
}
private onSuccess(): void {
this.failureCount = 0;
if (this.state === CircuitState.HALF_OPEN) {
this.successCount++;
if (this.successCount >= this.config.successThreshold) {
this.state = CircuitState.CLOSED;
this.successCount = 0;
}
}
}
private onFailure(): void {
this.failureCount++;
this.lastFailureTime = Date.now();
if (this.failureCount >= this.config.failureThreshold) {
this.state = CircuitState.OPEN;
this.nextAttempt = Date.now() + this.config.timeout;
}
}
getState(): CircuitState {
return this.state;
}
}
// Utilisation avec un service de paiement
const paymentCircuit = new CircuitBreaker({
failureThreshold: 5,
successThreshold: 2,
timeout: 60000,
monitoringPeriod: 10000
});
async function processPayment(amount: number) {
try {
return await paymentCircuit.execute(async () => {
const response = await fetch('https://api.payment.com/charge', {
method: 'POST',
body: JSON.stringify({ amount })
});
if (!response.ok) throw new Error('Payment failed');
return response.json();
});
} catch (error) {
// Fallback : logger et retourner une réponse par défaut
console.error('Payment service unavailable:', error);
return { status: 'pending', message: 'Retry later' };
}
}Mise en œuvre
- Identifier les points d'intégration critiques nécessitant une protection (API externes, bases de données, services tiers)
- Définir les seuils appropriés basés sur les SLA et les patterns de trafic observés
- Implémenter le pattern avec une bibliothèque éprouvée (Resilience4j, Polly, Opossum) ou une solution custom
- Configurer des stratégies de fallback adaptées au contexte métier (cache, réponse par défaut, dégradation gracieuse)
- Mettre en place une observabilité complète avec métriques sur les états, transitions et taux d'échec
- Tester les scénarios de défaillance et de récupération en environnement de staging
- Ajuster les paramètres en production selon les données réelles de performance
Conseil Pro
Combinez Circuit Breaker avec les patterns Retry et Timeout pour une stratégie de résilience complète. Utilisez un état Half-Open avec un nombre limité de requêtes test pour éviter de surcharger un service en récupération. Centralisez la configuration des circuit breakers dans un dashboard pour faciliter le monitoring et l'ajustement en temps réel.
Outils associés
- Resilience4j - bibliothèque Java légère avec support Circuit Breaker, Retry, Rate Limiter
- Polly - framework .NET pour la résilience et la gestion des erreurs transitoires
- Hystrix - bibliothèque Netflix (en maintenance) pionnière du pattern, référence historique
- Opossum - implémentation Node.js simple et performante du Circuit Breaker
- Istio/Envoy - circuit breakers intégrés au niveau du service mesh
- AWS App Mesh - gestion native des circuit breakers dans l'infrastructure cloud
L'adoption du pattern Circuit Breaker transforme la robustesse des architectures distribuées en convertissant les défaillances inévitables en comportements contrôlés et prévisibles. En protégeant proactivement contre les cascades d'erreurs, il garantit une disponibilité élevée et une expérience utilisateur cohérente, même dans les conditions les plus difficiles. Cette approche défensive devient indispensable dès lors que votre système dépend de services externes ou interconnectés.
