Modern microservice architectures improve scalability and team autonomy, but they also introduce a new challenge: service dependency failures.
If one service becomes slow or unavailable, it can easily cascade across the system, bringing down multiple services.
This is where the Circuit Breaker Pattern becomes extremely important.
In this article we will cover:
- The cascading failure problem
- How circuit breakers solve it
- Circuit breaker states
- A working example using Resilience4j
- Best practices when using circuit breakers
The Cascading Failure Problem
Imagine a simple microservice system:
Client → Order Service → Payment Service → Database
Now assume the Payment Service becomes slow or unavailable.
What happens?
- Order service keeps sending requests.
- Requests start waiting.
- Threads become blocked.
- System resources get exhausted.
- Eventually the Order Service also crashes.
This is called a cascading failure.
A single failure spreads across services.
The Circuit Breaker Concept
The concept is inspired by electrical circuit breakers.
When electrical current becomes dangerous, the circuit breaker cuts the flow to prevent damage.
Similarly in microservices, a circuit breaker:
- monitors failures
- stops sending requests temporarily
- allows the system to recover
Instead of continuously calling a failing service, we fail fast.
Circuit Breaker States
A circuit breaker typically has three states.
1️⃣ Closed State
Client → Order Service → Payment Service
- Requests flow normally
- Failures are monitored
- If failures exceed threshold → state changes
2️⃣ Open State
Client → Order Service ✖ Payment Service
- Calls are blocked immediately.
- No request is sent to failing service.
- System return a fallback response.
3️⃣ Half-Open State
Client → Order Service → Payment Service (limited test requests)
- Only a few requests allowed.
- If they succeed → circuit closes.
- If they fail → circuit opens again
Circuit Breaker Flow
Closed → Failures detected → Open
Open → Cooldown period → Half-Open
Half-Open → Success → Closed
Half-Open → Failure → Open
Implementing Circuit Breaker using Resilience4j
One of the most popular circuit breaker libraries in Java is Resilience4j.
It works very well with Spring Boot.
Add Dependency
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-spring-boot3</artifactId>
</dependency>
Configure Circuit Breaker
application.yml
resilience4j:
circuitbreaker:
instances:
paymentService:
registerHealthIndicator: true
slidingWindowSize: 10
minimumNumberOfCalls: 5
failureRateThreshold: 50
waitDurationInOpenState: 10s
Explanation:
-
slidingWindowSize→ number of calls monitored -
failureRateThreshold→ percentage to trigger breaker -
waitDurationInOpenState→ time before retry
Applying Circuit Breaker to a Service
Example: calling a Payment Service.
@Service
public class PaymentClient {
@CircuitBreaker(name = "paymentService", fallbackMethod = "fallbackPayment")
public String processPayment() {
// call external payment service
return restTemplate.getForObject(
"http://payment-service/pay",
String.class
);
}
public String fallbackPayment(Throwable ex) {
return "Payment service unavailable. Please try later.";
}
}
What happens here:
- Calls go normally.
- If failure rate exceeds threshold → circuit opens.
- All calls go directly to fallback method.
What a Fallback Response Looks Like
Fallback responses prevent system crashes.
{
"status": "FAILED",
"message": "Payment service temporarily unavailable"
}
Instead of crashing, the system degrades gracefully.
When Should You Use Circuit Breakers?
Circuit breakers are useful when:
- calling external APIs.
- calling slow microservices.
- interacting with unreliable networks.
Typical examples:
Order Service → Payment Service
Checkout Service → Inventory Service
API Gateway → User Service
When NOT to Use Circuit Breakers
Avoid using circuit breakers for:
- database calls inside the same service
- very fast local operations
- in-memory calls
Circuit breakers are best suited for remote network calls.
Best Practices
✔ Always define fallback responses
✔ Monitor breaker metrics
✔ Combine with retry mechanism
✔ Use timeouts with circuit breakers
Final Thoughts
Microservices improve scalability and flexibility, but they also introduce reliability challenges when services depend on each other. A failure in one service can quickly propagate and lead to cascading failures across the system.
The Circuit Breaker Pattern helps prevent this by stopping repeated calls to failing services and allowing systems to fail fast with fallback responses. Tools like Resilience4j make it easy to implement this pattern in Spring Boot applications.
In the next article, we’ll explore building production-grade resilience using Resilience4j, including retries, bulkheads, and other advanced patterns.
Stay tuned for the next part of this series 🚀
Top comments (0)