Resilience4j is a library designed to guarantee application availability, mainly in high-load environments. With the rise of Microservices, it has become essential to control what happens when one of our services fails or is slow to respond, preventing a "cascading failure."
What is a Circuit Breaker?
The Circuit Breaker pattern works similarly to electrical breakers in a house. If it detects a failure, it "opens" the circuit to prevent further damage and "closes" it once the problem is resolved.
A Circuit Breaker has three main states:
- Closed: Everything is working correctly. Requests flow normally.
- Open: Failures have exceeded the allowed threshold. Requests are blocked and a fallback is executed.
- Half-Open: A trial period where a limited number of requests are allowed to check if the service has recovered.
1. Resilience4j Configuration
To start, we create a Spring Boot project and add the following dependency:
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-spring-boot2</artifactId>
</dependency>
In our application.yml, we define the parameters that will govern the behavior of our Circuit Breaker:
resilience4j:
circuitbreaker:
instances:
mainService:
registerHealthIndicator: true
slidingWindowSize: 10
permittedNumberOfCallsInHalfOpenState: 3
slidingWindowType: COUNT_BASED
minimumNumberOfCalls: 5
waitDurationInOpenState: 10s
failureRateThreshold: 50
eventConsumerBufferSize: 10
Parameter Breakdown:
- slidingWindowSize: The number of calls to record when the circuit is closed.
- failureRateThreshold: The percentage of failures (e.g., 50%) at which the circuit should open.
- waitDurationInOpenState: How long the circuit stays "Open" before trying to recover.
- permittedNumberOfCallsInHalfOpenState: Number of successful calls needed in "Half-Open" to close the circuit again .
2. Implementation with Annotations
The easiest way to use it is by using the @CircuitBreaker annotation. We must specify the name of the instance we configured in the YAML and a fallback method.
Note: The fallback method must have the same signature as the original method, but it must also receive a Throwable or Exception as an argument.
2. Implementation with Annotations
The easiest way to use it is by using the @CircuitBreaker annotation. We must specify the name of the instance we configured in the YAML and a fallback method.
Note: The fallback method must have the same signature as the original method, but it must also receive a Throwable or Exception as an argument.
@Service
public class ProductService {
@CircuitBreaker(name = "mainService", fallbackMethod = "fallbackGetProducts")
public List<Product> getProducts() {
// Logic that might fail (e.g., calling an external API)
return externalApi.fetchProducts();
}
// Fallback Method
public List<Product> fallbackGetProducts(Throwable e) {
return List.of(new Product("Default Product", 0.0));
}
}
3. Other Resilience4j Modules
While the Circuit Breaker is the most famous, Resilience4j offers other tools to improve stability:
TimeLimiter
Used to set a maximum execution time for a request. If the service doesn't respond within the timeframe, it triggers a failure.
Retry
Allows us to automatically retry a failed operation a specific number of times before giving up.
Bulkhead
Limits the number of concurrent calls to a service to avoid saturating resources (like thread pools).
Conclusions
Resilience4j is a powerful tool for building robust Microservices. By implementing the Circuit Breaker pattern, we ensure that our application can fail gracefully instead of crashing completely under pressure.
Top comments (0)