Circuit Breaker Pattern
Contents
Circuit Breaker Pattern
It prevents cascading failures by stopping calls to a failing service once errors cross a threshold. It provides fallback mechanisms to keep the system stable even when dependencies fail like a safety switch.
Example: Suppose your online store depends on a payment service. If that service starts failing repeatedly, the circuit breaker “trips” and stops further calls for a while, preventing cascades and giving the service time to recover.
Characteristics
- Improves fault tolerance by isolating failing dependencies.
- Monitors latency, error rate, and timeouts over a rolling window.
- Prevents cascades by temporarily stopping calls to an unhealthy service.
- Supports fallbacks (default responses, cached data, queueing) for graceful degradation.
- Auto-recovers by probing and resetting when the service stabilizes.
Different states:
- Closed State
- In the Closed state, the circuit breaker operates normally, allowing requests to flow through between services.
- Open State
- When the monitored metrics breach predetermined thresholds, signaling potential issues with the downstream service, the circuit breaker transitions to the Open state.
- In the Open state, the circuit breaker immediately stops forwarding requests to the failing service, effectively isolating it.
- Half-Open State
- After a specified timeout period in the Open state, transitions to Half-Open state.
- Allows a limited number of trial requests to pass through to the downstream service.
- Monitors responses to determine service recovery.
- If trial requests succeed, indicating service recovery, transitions back to Closed state.
- If trial requests fail, service issues persist.
- May transition back to Open state or remain in Half-Open state for further evaluation.
Libraries for implementation: Resilience4j, Spring Cloud Circuit Breaker, Hystrix (in maintenance mode)
Example in a Spring boot application
Maven dependency (pom.xml)
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-spring-boot3</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>Configuration (application.yaml)
resilience4j:
circuitbreaker:
instances:
userService:
registerHealthIndicator: true
slidingWindowSize: 10
minimumNumberOfCalls: 5
failureRateThreshold: 50
waitDurationInOpenState: 10s
permittedNumberOfCallsInHalfOpenState: 3
slidingWindowType: COUNT_BASEDUsage
@Service
public class UserService {
private final RestTemplate restTemplate;
public UserService(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
// name must match the instance name in application.yml
@CircuitBreaker(name = "userService", fallbackMethod = "getUserFallback")
public String getUserData(String userId) {
return restTemplate.getForObject("http://external-service/users/" + userId, String.class);
}
// Fallback must have the same signature + Throwable
public String getUserFallback(String userId, Throwable t) {
return "Fallback response: Service is currently unavailable.";
}
}