Circuit Breaker Half-Open
L'état test du Circuit Breaker — celui qui évite le yo-yo entre Open et Closed et qui rend le pattern utilisable en production.
Problème
Un Circuit Breaker basique a deux états : Closed (trafic passe) ou Open (trafic bloqué). Quand le partenaire AS2 Walmart est en erreur, le circuit s'ouvre après 5 échecs en 10s, blocage 30s, puis on retente. Si Walmart répond avec une erreur (encore en panne), le circuit se referme aussitôt — et 5 nouvelles requêtes essaient, échouent, le circuit ré-ouvre. Toutes les 30s, un burst de 5 requêtes traverse : on a inventé un système qui DDoS le partenaire dès qu'il revient en ligne. Pire : les transitions Open ↔ Closed flippent en boucle.
Forces
- Tester avant de rouvrir est nécessaire. Sans sonde, on ne sait pas si le partenaire est revenu.
- Le test ne doit pas être massif. Si on envoie tout le trafic d'un coup et que le partenaire est fragile, on le retombe.
- Le test doit échantillonner sans bloquer. Le service applicatif ne doit pas être bloqué pendant le test.
- Plusieurs tests peuvent être nécessaires. Une seule requête en succès n'est pas une preuve de stabilité.
Solution
Ajouter un état intermédiaire Half-Open au Circuit Breaker. Quand le timer d'Open expire, on passe à Half-Open. Dans cet état, on autorise au maximum N requêtes-test simultanées (typiquement 1 à 3). Les autres continuent à recevoir un fail-fast 503. Si les M premières requêtes-test (typiquement M=N=3) réussissent, on retourne à Closed : trafic plein. Si une requête échoue, on retombe immédiatement à Open et on relance un timer (souvent plus long, en backoff exponentiel). Resilience4j, Polly, Istio implémentent cet état nativement.
[Closed]
trafic OK
│
threshold dépassé
(ex: 5 échecs/10s)
│
▼
[Open] ◀───── échec sur 1 requête-test
trafic bloqué │
fail-fast 503 │
│ │
timer reset (ex: 30s) │
│ │
▼ │
[Half-Open] │
N requêtes-test ───────────────────── │
(ex: 3 max simultanées) │
│ │
M succès consécutifs │
│ │
▼ │
[Closed] ──── trafic plein ──────── │
Implémentation EDI
Cas concret : hub EDI Java avec Resilience4j. Configuration circuitBreaker.walmart-as2 : failureRateThreshold=50%, slidingWindowSize=20, waitDurationInOpenState=30s, permittedNumberOfCallsInHalfOpenState=3. À 11h
Walmart commence à répondre HTTP 503. Vers 11h00:18, le circuit
passe à Open. Tout AS2 vers Walmart répond immédiatement CircuitBreakerOpenException, le service applicatif
redirige sur une queue de retry. À 11h00:48, le circuit passe à
Half-Open. Les 3 premiers messages AS2 sont envoyés. Walmart répond
200 OK pour les 3 : circuit revient à Closed, trafic complet
reprend. Si l'un des 3 avait échoué, Half-Open repasse à Open avec
timer doublé à 60s. Sur la console ops, on voit le diagramme
d'état en temps réel — métriques Prometheus resilience4j_circuitbreaker_state.
Anti-patterns
- Pas de Half-Open. Circuit qui flippe entre Closed et Open en boucle dès que le partenaire est instable : bursts de retry, partenaire qui s'effondre dès qu'il rouvre.
- Half-Open avec trop de requêtes-test. Si N=100, on a juste retardé le DDoS de 30s.
- Half-Open sans backoff cumulatif. Si chaque retour à Open relance toujours 30s, et que le partenaire reste down 4h, on génère 480 bursts de test. Doubler le timer à chaque échec.
- Half-Open en lecture seule. On teste avec un
GET /healthmais on bascule le trafic d'écriture automatiquement : le partenaire peut avoir une santé OK et un pipeline d'écriture cassé. Tester avec une requête représentative.
Patterns liés
- Circuit Breaker — le pattern parent.
- Retry + backoff — le backoff exponentiel s'applique au timer Open après chaque échec.
- Health Check — la requête-test envoyée en Half-Open est parfois un health-check.
- Bulkhead — un Circuit Breaker par compartiment.
- Timeout — chaque requête-test a son propre timeout, distinct du circuit.
Sources
- Nygard M. — Release It!, Pragmatic Bookshelf, 2e éd. 2018. Chap. « Circuit Breaker » détaille les trois états. pragprog.com — Release It! 2nd ed
- Fowler M. — CircuitBreaker (martinfowler.com, 2014). La synthèse pédagogique avec un diagramme d'état canonique. martinfowler.com — CircuitBreaker
- Resilience4j — CircuitBreaker. Implémentation Java de référence avec état Half-Open paramétrable. resilience4j.readme.io/docs/circuitbreaker
- Polly — Circuit Breaker. L'implémentation .NET. thepollyproject.org
- Istio — Circuit Breaking. La config
outlierDetectiondu mesh implémente la transition. istio.io — Circuit Breaking