// Resilience & Messaging · 05
Circuit Breaker
Stop calling a service that's already drowning, so it can recover.
How it fits together
- Checkout uses / calls Closed (calls)
- Closed fails / error path Open (failures ≥ 50%)
- Open uses / calls Half-open (after 15s)
- Half-open fails / error path Open (trial fails)
- Half-open uses / calls Closed (trial ok)
- Closed uses / calls Payments service (2 call)
- Half-open uses / calls Payments service (2 trial call)
Spot it
- Every request waits out the full timeout
- A dead dependency still gets hammered
- Threads pile up behind one broken service
It costs
While open, even requests that would have succeeded are rejected.
In code
services.AddHttpClient<PaymentsClient>() .AddResilienceHandler("payments", pipeline => { pipeline.AddCircuitBreaker(new HttpCircuitBreakerStrategyOptions { FailureRatio = 0.5, MinimumThroughput = 20, SamplingDuration = TimeSpan.FromSeconds(30), BreakDuration = TimeSpan.FromSeconds(15), ShouldHandle = args => ValueTask.FromResult( args.Outcome.Exception is not null || (int?)args.Outcome.Result?.StatusCode is 408 or 429 or >= 500), }); });Go deeperThe full explanation and what to ask for · 1 min readExpandCollapse
Closed: calls flow and failures are counted. Open: calls fail immediately without touching the dependency. Half-open: after the break duration, a trial call decides whether to close again or reopen.
The classic mistakes are thresholds that never trip at low traffic (hence a minimum throughput) and counting the wrong failures: a 404 or a validation error says nothing about the health of the dependency. Use one breaker per downstream dependency, not one shared breaker for everything.
Retries absorb short blips; the breaker stops them from hammering a long outage. Pair it with a timeout, since a breaker only sees failures it is told about, and with a fallback such as cached data or a degraded feature.
Ask for it
- closed / open / half-open
- failure ratio
- minimum throughput
- sampling duration
- break duration
- fallback
Add a circuit breaker to the payments client: open when 50% of at least 20 calls fail within 30s, stay open 15s, then let one trial call through. While open, return 503 with Retry-After and log every state change.