Problem with circuit breaker in asynch mode
See original GitHub issueHi all.
I have some problems regarding the transition from half_open to close state when using asynch mode (using version 0.15.0). Here is my code
CircuitBreakerConfig circuitBreakerConfig =
CircuitBreakerConfig.custom()
.failureRateThreshold(50.0F)
.waitDurationInOpenState(Duration.ofMillis(1 * 30 * 1000))
.ringBufferSizeInHalfOpenState(2)
.ringBufferSizeInClosedState(3)
.ignoreExceptions(BusinessException.class)
.build();
CircuitBreakerRegistry circuitBreakerRegistry = CircuitBreakerRegistry.of(circuitBreakerConfig);
circuitBreaker = circuitBreakerRegistry.circuitBreaker("circuit breaker", circuitBreakerConfig);
circuitBreaker.getEventPublisher()
.onStateTransition(event -> {
System.out.println("CIRCUIT BREAKER " + event.getStateTransition().toString());
});
public void doRun(long messageID) {
System.out.println("CIRCUIT BREAKER IS " + circuitBreaker.getState());
Supplier<CompletionStage<Void>> completionStageSupplier = () -> CompletableFuture.supplyAsync(() -> {
try {
return service.execute(messageID);
} catch (Exception e) {
throw new CompletionException(e);
}
});
CompletionStage<Void> completionStage = Decorators.ofCompletionStage(completionStageSupplier)
// .withRetry(retry, Executors.newSingleThreadScheduledExecutor())
.withCircuitBreaker(circuitBreaker)
.get();
try {
Try.ofSupplier(() -> completionStage.toCompletableFuture()).recover(throwable -> {
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
recovery(throwable);
});
return future;
}).get().get(30, TimeUnit.SECONDS);
} catch (Exception e) {
System.out.println("try exception " + e);
}
}
Here is my scenario: My application sends a message every 10 seconds, so that the method doRun(messageID) get called for each new message. The service , in a first time, returns no exception, so that the circuit is CLOSED.
[x] Sent '{"id":1,"message":"order"}
CIRCUIT BREAKER IS CLOSED
response is pong 1 ( _here the response of the service called_)
Now, i disable the service so that it returns an exception.
CIRCUIT BREAKER State transition from CLOSED to OPEN
[x] Sent '{"id":10,"message":"order"}
CIRCUIT BREAKER IS OPEN
try exception java.util.concurrent.ExecutionException: io.github.resilience4j.circuitbreaker.CallNotPermittedException: CircuitBreaker 'circuit breaker' is OPEN and does not permit further calls
So far so good. Then, i restablish the service. After the delay , the state goes to HALF_OPEN as expected
[x] Sent '{"id":13,"message":"order"}
CIRCUIT BREAKER IS HALF_OPEN
response is pong 13
[x] Sent '{"id":14,"message":"order"}
CIRCUIT BREAKER IS HALF_OPEN
response is pong 14
Still good. But after these 2 tries, i expect the circuit breaker to go to the CLOSED state after the next message. But here is the result:
[x] Sent '{"id":16,"message":"order"}
CIRCUIT BREAKER IS HALF_OPEN
try exception java.util.concurrent.ExecutionException: io.github.resilience4j.circuitbreaker.CallNotPermittedException: CircuitBreaker 'circuit breaker' is HALF_OPEN and does not permit further calls
By teh way, is there something wrong with my call to recovery method ? it’s never called…
I have no problem in synch mode with this code:
CheckedFunction0<Void> checkedSupplier = Retry.decorateCheckedSupplier(retry, () -> service.execute(messageID));
checkedSupplier = CircuitBreaker.decorateCheckedSupplier(circuitBreaker, checkedSupplier);
Try.of(checkedSupplier)
.recover(this::recovery).get();
Thanks for your help!
Issue Analytics
- State:
- Created 4 years ago
- Comments:11 (8 by maintainers)
Top GitHub Comments
Currently a
TimeLimiter
can only decorate aFuture<T>
orCompletableFuture<T>
and converts it into aCallable<T>
. You can’t use it to decorate aCompletionStage
.But you could do the following:
The problem is here https://github.com/resilience4j/resilience4j/blob/master/resilience4j-circuitbreaker/src/main/java/io/github/resilience4j/circuitbreaker/CircuitBreaker.java#L478 If you decorate a CompletionStage<Void>, the result is always
null
.