Spring boot resilience4j circuit breaker fallback method not being called

1.4k Views Asked by At

In my project, I followed instructions from tutorial and ended up with a not working circuit breaker. Here is the code: application.properties

## circuit breaker
management.endpoints.web.exposure.include=*
management.endpoint.health.show-details=always
management.health.circuitbreakers.enabled=true

resilience4j.circuitbreaker.instances.reservation.failure-rate-threshold=50
resilience4j.circuitbreaker.instances.reservation.minimum-number-of-calls=5
resilience4j.circuitbreaker.instances.reservation.automatic-transition-from-open-to-half-open-enabled=true
resilience4j.circuitbreaker.instances.reservation.wait-duration-in-open-state=5s
resilience4j.circuitbreaker.instances.reservation.permitted-number-of-calls-in-half-open-state=3
resilience4j.circuitbreaker.instances.reservation.sliding-window-size=10
resilience4j.circuitbreaker.instances.reservation.sliding-window-type=count_based
resilience4j.circuitbreaker.configs.default.registerHealthIndicator=true

NotificationController.java

@RestController
@RequestMapping("/api/notification")
public class NotificationApiController {

    @Autowired
    private NotificationService notificationService;

    @PostMapping
    @ResponseStatus(HttpStatus.OK)
    @CircuitBreaker(name = "reservation", fallbackMethod = "fallbackMethod")
    public void createNotificationsAboutUpcomingDeadlines() {
        notificationService.createNotificationsAboutUpcomingDeadlines();
    }

    public void fallbackMethod(RuntimeException runtimeException) {
        System.out.println("Not working");
    }
}

and the fragment of NotificationService that is calling another microservice:

    private List<BookDto> queryCatalogServiceForItemsDetails(List<ReservationDto> reservationItemDtoList){
        List<Integer> bookIsbnList = reservationItemDtoList.stream()
                .flatMap(reservation -> reservation.getReservationItemList().stream())
                .map(ReservationItemDto::getBookIsbn)
                .collect(Collectors.toList());

        Object[] x = webClientBuilder.build().get()
                .uri(String.format("http://catalogService/api/catalog?ids=%s", bookIsbnList.stream()
                        .map(Object::toString)
                        .collect(Collectors.joining(", "))))
                .retrieve()
                .bodyToMono(Object[].class)
                .block();
        return Arrays.stream(x)
                .map(object -> mapper.convertValue(object, BookDto.class))
                .collect(Collectors.toList());
    }

The problem is that when the catalogService is down, the notificationService ends up with: java.net.ConnectException: Connection refused: no further information Instead of triggering fallback method. Any ideas why?

1

There are 1 best solutions below

0
Raghvendra Garg On

according to Resilience4j Doc.

The fallback method mechanism works like a try/catch block. If a fallback method is configured, every exception is forwarded to a fallback method executor. The fallback method executor is searching for the best matching fallback method that can handle the exception. Similar to a catch block. The fallback is executed independently of the current state of the circuit breaker.

Your fallback method will be invoked when createNotificationsAboutUpcomingDeadlines throws a RuntimeException and since ConnectException is not a runtime exception so fallback is not getting invoked, if you want to catch all Exceptions change the fallback method like below.

public void fallbackMethod(Exception exception) {
    System.out.println("Not working");
}