CircuitBreaker does not prevent execution of upstream Mono if flatMap is used
See original GitHub issueExpected behavior
Both tests simple
, withMap
, and withFlatMap
behave the same.
Actual behavior
In simple
and withMap
getNext()
is called twice (as expected) and withFlatMap
getNext()
is called four times.
Log for simple
/withMap
test
Requested Counter: 1
16:03:19.461 [main] DEBUG io.github.resilience4j.circuitbreaker.internal.CircuitBreakerStateMachine - No Consumers: Event SUCCESS not published
Ctr: 1
Requested Counter: 2
16:03:19.476 [main] DEBUG io.github.resilience4j.circuitbreaker.internal.CircuitBreakerStateMachine - CircuitBreaker 'test' recorded a failure:
java.lang.RuntimeException: Error
...
16:03:19.477 [main] DEBUG io.github.resilience4j.circuitbreaker.internal.CircuitBreakerStateMachine - No Consumers: Event ERROR not published
16:03:19.494 [main] DEBUG io.github.resilience4j.circuitbreaker.internal.CircuitBreakerStateMachine - No Consumers: Event STATE_TRANSITION not published
RuntimeException
16:03:19.496 [main] DEBUG io.github.resilience4j.circuitbreaker.internal.CircuitBreakerStateMachine - No Consumers: Event NOT_PERMITTED not published
CircuitBreakerOpenException
16:03:19.497 [main] DEBUG io.github.resilience4j.circuitbreaker.internal.CircuitBreakerStateMachine - No Consumers: Event NOT_PERMITTED not published
CircuitBreakerOpenException
Log for withFlatMap
test
Requested Counter: 1
16:03:19.601 [main] DEBUG io.github.resilience4j.circuitbreaker.internal.CircuitBreakerStateMachine - No Consumers: Event SUCCESS not published
Ctr: 1
Requested Counter: 2
16:03:19.603 [main] DEBUG io.github.resilience4j.circuitbreaker.internal.CircuitBreakerStateMachine - CircuitBreaker 'test' recorded a failure:
java.lang.RuntimeException: Error
...
16:03:19.603 [main] DEBUG io.github.resilience4j.circuitbreaker.internal.CircuitBreakerStateMachine - No Consumers: Event ERROR not published
16:03:19.603 [main] DEBUG io.github.resilience4j.circuitbreaker.internal.CircuitBreakerStateMachine - No Consumers: Event STATE_TRANSITION not published
RuntimeException
Requested Counter: 3
16:03:19.603 [main] DEBUG io.github.resilience4j.circuitbreaker.internal.CircuitBreakerStateMachine - No Consumers: Event NOT_PERMITTED not published
CircuitBreakerOpenException
Requested Counter: 4
16:03:19.604 [main] DEBUG io.github.resilience4j.circuitbreaker.internal.CircuitBreakerStateMachine - No Consumers: Event NOT_PERMITTED not published
CircuitBreakerOpenException
Steps to reproduce
public class Resilience4jSimpleTest {
int counter = 0;
CircuitBreakerConfig breakerConfig = CircuitBreakerConfig.custom()
.ringBufferSizeInClosedState(2)
.build();
CircuitBreaker circuitBreaker = CircuitBreaker.of("test", breakerConfig);
@Test
public void simple() {
System.out.println(performCall(circuitBreaker));
System.out.println(performCall(circuitBreaker));
System.out.println(performCall(circuitBreaker));
System.out.println(performCall(circuitBreaker));
}
@Test
public void withMap() {
System.out.println(performCallWithMap(circuitBreaker));
System.out.println(performCallWithMap(circuitBreaker));
System.out.println(performCallWithMap(circuitBreaker));
System.out.println(performCallWithMap(circuitBreaker));
}
@Test
public void withFlatMap() {
System.out.println(performCallWithFlatMap(circuitBreaker));
System.out.println(performCallWithFlatMap(circuitBreaker));
System.out.println(performCallWithFlatMap(circuitBreaker));
System.out.println(performCallWithFlatMap(circuitBreaker));
}
String getNext() {
counter++;
System.out.println("Requested Counter: " + counter);
if (counter % 2 == 0) {
throw new RuntimeException("Error");
}
return "Ctr: " + counter;
}
private String performCall(CircuitBreaker circuitBreaker) {
return Mono.fromCallable(this::getNext)
.transform(CircuitBreakerOperator.of(circuitBreaker))
.onErrorResume(Exception.class, (e) -> Mono.just(e.getClass().getSimpleName()))
.block();
}
private String performCallWithMap(CircuitBreaker circuitBreaker) {
return Mono.fromCallable(this::getNext)
.map(Function.identity())
.transform(CircuitBreakerOperator.of(circuitBreaker))
.onErrorResume(Exception.class, (e) -> Mono.just(e.getClass().getSimpleName()))
.block();
}
private String performCallWithFlatMap(CircuitBreaker circuitBreaker) {
return Mono.fromCallable(this::getNext)
.flatMap(Mono::just)
.transform(CircuitBreakerOperator.of(circuitBreaker))
.onErrorResume(Exception.class, (e) -> Mono.just(e.getClass().getSimpleName()))
.block();
}
}
Versions
- resilience4j 0.13.2
- reactor: 3.2.6.Final
Possible related #334 issue
Issue Analytics
- State:
- Created 5 years ago
- Comments:11 (11 by maintainers)
Top Results From Across the Web
Mono.flatMap is not getting invoked - Stack Overflow
I inserted the print statement to test if it prints anything and it doesn't even execute the print statement. publishToTopic returns Mono<Void> ...
Read more >Spring Cloud Gateway
This project provides an API Gateway built on top of the Spring Ecosystem, including: Spring 5, Spring Boot 2 and Project Reactor. Spring...
Read more >Mono (reactor-core 3.5.0)
If an onErrorContinue(BiConsumer) variant has been used downstream, reverts to the default 'STOP' mode where errors are terminal events upstream. Mono<T> ...
Read more >reactor.core.publisher.Mono.delayElement java code examples
Delay this Mono element ( Subscriber#onNext signal) by a given duration. Empty Monos or error signals are not delayed.
Read more >Management & Monitoring - Micronaut Documentation
Please keep in mind that starting with 21.3.0 GraalVM doesn't release a version based on JDK 8. If you still use Java 8...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
This will be fixed in the next release.
This test is successful now