A circuit breaker protects an application from repeatedly calling a dependency that is already failing. Rather than letting timeouts or errors keep consuming work, it detects excessive failures, opens the circuit, and rejects new calls immediately for a defined period. This gives the dependency time to recover and prevents it from being overwhelmed further. section 7.2.4 section 9.2
Use it after recognizing that a remote call is unreliable and that retries alone have not restored service. While the circuit is open, choose an acceptable fallback: return a cached response when that remains useful, or provide a clear, actionable error. A fallback should preserve the intended business behavior rather than quietly hide a failure. section 7.2.4
The recovery cycle is deliberately limited:
- Observe calls and count failures over a configured evaluation window. section 7.2.4
- Open the circuit when failures exceed the chosen threshold, short-circuiting later calls instead of contacting the dependency. section 7.2.4
- Wait through a cooling-off period, then test whether the dependency has recovered. section 7.2.4
- Restore communication on recovery; otherwise keep the circuit open. section 7.2.4
Guarding a payment-service call
A Resilience4J configuration can make the policy visible: set a 50% failure-rate threshold, evaluate a sliding window of five calls with at least five calls required, and wait briefly while open. Register a circuit breaker named for the payment service, then decorate the supplier that performs the call. Once the configured failure rate is crossed, subsequent calls are rejected immediately rather than sent to the unreliable service. section 7.2.4
A circuit breaker is one resilience pattern, not a universal replacement for other controls. Retries and fallbacks address failed operations; rate limiters, backpressure, bulkheads, and time limiters regulate demand or contain pressure. Caches can both reduce dependency load and support service during partial outages. Select and combine them according to whether the immediate problem is failure recovery, overload, isolation, or degraded service. section 9.2
Listing 7.2 CircuitBreaker example
public Supplier<String> getPaymentServiceWithCircuitBreaker() {
CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig #1
.custom() #1
.failureRateThreshold(50) #1
.waitDurationInOpenState(Duration.ofMillis(5)) #1
.slidingWindowSize(5) #1
.minimumNumberOfCalls(5) #1
.build(); #1
CircuitBreaker circuitBreaker = #2
CircuitBreakerRegistry #2
.of(circuitBreakerConfig) #2
.circuitBreaker("paymentService"); #2
return CircuitBreaker #3
.decorateSupplier(circuitBreaker, #3
getUnreliableService()); #3
}
Inspect the configuration-and-decoration example to see how a readable builder expresses failure threshold, open duration, sliding window, and the protected payment-service call. section 7.2.4
As a design pattern, Circuit Breaker names a reusable response to a specific distributed-systems problem: improving resilience when a dependency fails. The pattern is not tied to one programming language or framework, and it should guide design rather than be applied mechanically. Libraries can supply the implementation, but the thresholds, recovery timing, and fallback still require context-sensitive choices. section 9.1.3 section 7.2.4





