Implementing Circuit Breaker pattern using Resilience4J | Fault Tolerance | SpringBoot Microservices
We have a UserService microserviece which is makes call to other microservices and we would like to implement circuit breaker pattern here.
Step 1 → Add dependencies -
Spring Boot Actuator | OPS → To monitor the health of our microservice application.
Starter AOP → To be able to send matrics.
resilience4j-spring-boot3 (Check the one applicable to your SpringBoot and Java version)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-aop -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>3.3.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.github.resilience4j/resilience4j-spring-boot3 -->
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-spring-boot3</artifactId>
<version>2.2.0</version>
</dependency>
Step 3 → Add @CircuitBreaker to the controller method that makes call to other microservices. We will also give “name” and a “fallback“ method for this method.
@CircuitBreaker(name="RATING_HOTEL_BREAKER", fallbackMethod="ratingHotelFallback")
@GetMapping("{userId}")
public ResponseEntity<UserEntity> getUser (@PathVariable String userId){
UserEntity tempUser = userService.getUser(userId);
Rating [] ratings = ratingService.getAllRatings(userId);
List<Rating> allRatings = Arrays.stream(ratings).toList();
tempUser.setRatings(allRatings);
return ResponseEntity.ok(tempUser);
}
Step 4 → Implement the fallback method. The fallback method runs when the RatingService microservice is down and cannot send response. In such case after a certain number of attempts the circuit pattern will trip and the dummy response from the fallback method will be sent.
Fallback method must have the same return type and parameters as the original API method. Also fallback method must have a parameter of type Exception.
public ResponseEntity<UserEntity> ratingHotelFallback (String userId, Exception ex){
UserEntity user = UserEntity.builder()
.userId("12345")
.name("Dummy User")
.email("Dummy@dev.com")
.about("This is a dummy user.")
.build();
System.out.println("Something went wrong : "+ex);
return new ResponseEntity<>(user, HttpStatus.OK);
}
Step 5 → Add configurations
Actuator configuration -
management.health.circuitbreakers.enabled=true management.endpoints.web.exposure.include=health management.endpoint.health.show-details=always
resilience4j configuration - (“RATING_HOTEL_BREAKER“ in below configurations is the name we gave to the API method in Step 3.)
resilience4j.circuitbreaker.instances.RATING_HOTEL_BREAKER.register-health-indicator=true resilience4j.circuitbreaker.instances.RATING_HOTEL_BREAKER.event-consumer-buffer-size=10 resilience4j.circuitbreaker.instances.RATING_HOTEL_BREAKER.failure-rate-threshold=50 resilience4j.circuitbreaker.instances.RATING_HOTEL_BREAKER.minimum-number-of-calls=5 resilience4j.circuitbreaker.instances.RATING_HOTEL_BREAKER.automatic-transition-from-open-to-half-open-enabled=true resilience4j.circuitbreaker.instances.RATING_HOTEL_BREAKER.wait-duration-in-open-state=6s resilience4j.circuitbreaker.instances.RATING_HOTEL_BREAKER.permitted-number-of-calls-in-half-open-state=3 resilience4j.circuitbreaker.instances.RATING_HOTEL_BREAKER.sliding-window-size=10 resilience4j.circuitbreaker.instances.RATING_HOTEL_BREAKER.sliding-window-type=COUNT_BASED
Let’s test now. If our RatingService is down and we hit the UserService API to get user by userId, we get this dummy response from the fallback method we implemented -
We can check the Circuit Breaker details from the actuator health end point ( http://localhost:8081/actuator/health ) -