Resilience4j: circuit breaker can be called without affecting the state.

Created on 10 Feb 2020  路  5Comments  路  Source: resilience4j/resilience4j

Resilience4j version: 1.3.1

Java version: 1.8

I just want to know the circuit breakers status. ex) is open or half-open and can call backend).
so I used tryAcquirePermission(). but I missed the comment below.

     * Important: Make sure to call onSuccess or onError after the call is finished.
     * If the call is canceled before it is invoked, you have to release the permission again.

so everything is looks fine until the circuit breaker is half-open.
when circuit breaker is half-open, to call tryAcquirePermission is effect permittedNumberOfCallsInHalfOpenState. ( Using this method affects this property.)
if call count reached permittedNumberOfCallsInHalfOpenState, circuit breaker stuck half-open

I think need to make a method to check to call permitted a backend service.
If possible, I want to make it.

Most helpful comment

You can create a method like this:

private <T> Mono<T> executeWithFallback(Mono<T> publisher, Function<Throwable, Mono<T>> fallback){
        return publisher
                .transform(TimeLimiterOperator.of(timeLimiter))
                .transform(CircuitBreakerOperator.of(circuitBreaker))
                .onErrorResume(TimeoutException.class, fallback)
                .onErrorResume(CallNotPermittedException.class, fallback);
    }

The fallback can be your message to the user.

Mono<T> result = executeWithFallback(() -> yourService.method(), () ->  Mono.empty());

All 5 comments

Hi,

you can use CircuitBreakerUtil.isCallPermitted(circuitBreaker) for this.

@RobWin I used CircuitBreakerUtil.isCallPermitted(circuitBreaker) :)
but I found some issue.

see the code below

   fun call(cnt: Int): Mono<Boolean> {
        if (!CircuitBreakerUtil.isCallPermitted(circuitBreaker)) {  //  1) check to call permitted
            return true.toMono() // In production, we returns message for user. for example a can not use the feature, please try later
        }
        return Mono.just(throwEnable) // 2) if call permitted, call backend.
                .flatMap {
                    if (it) {
                        Mono.error(ApiException(ErrorCd.INTERNAL_ERROR)) // 3) if backend throw exception and reached failed count, the circuit breaker is OPEN.
                    } else {
                        it.toMono()
                    }
                }
                .transform(CircuitBreakerOperator.of(circuitBreaker))
                .onErrorResume {
                    Mono.empty()
                }
                .doOnSubscribe {
                    log.info("cnt: $cnt circuit breaker status: ${circuitBreaker.state}")
                }
    }

if the circuit breaker is OPEN, it never changes state to half-open.
because don't call tryAcquirePermission().

What should I do in this case?

Hi @chayu07
There is automaticTransitionFromOpenToHalfOpenEnabled property.
If set to true, CircuitBreaker will automatically transition from open to half-open state.

This is not how you should use the CircuitBreaker. The exception from the CircuitBreaker tells you that it is open, just map the exception to a proper response to the user. Please don't do it that way.
There is usually no need to use this CircuitBreakerUtil class.

You can create a method like this:

private <T> Mono<T> executeWithFallback(Mono<T> publisher, Function<Throwable, Mono<T>> fallback){
        return publisher
                .transform(TimeLimiterOperator.of(timeLimiter))
                .transform(CircuitBreakerOperator.of(circuitBreaker))
                .onErrorResume(TimeoutException.class, fallback)
                .onErrorResume(CallNotPermittedException.class, fallback);
    }

The fallback can be your message to the user.

Mono<T> result = executeWithFallback(() -> yourService.method(), () ->  Mono.empty());
Was this page helpful?
0 / 5 - 0 ratings