Resilience4j-rxjava2 doesn't report CircuitBreaker success metrics post 0.15.0 upgrade
See original GitHub issueWith the 0.15.0 upgrade, we have noticed that success events are no longer reported for our RxJava2 circuits.
0.14.1 code:
CircuitBreakerConfig config = CircuitBreakerConfig.custom()
.ringBufferSizeInClosedState(10)
.ringBufferSizeInHalfOpenState(5)
.waitDurationInOpenState(Duration.ofMillis(10000))
.failureRateThreshold(0.50f)
.build();
CircuitBreaker breaker1 = CircuitBreaker.of("one", config);
breaker1.getEventPublisher()
.onEvent(r4jEvent -> System.out.println(String.format("Got an event %s for Circuit %s",
r4jEvent, breaker1)));
for (int i = 0; i < 10; i++) {
final int index = i;
String output = Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> emitter) throws Exception {
if (index % 2 == 0) {
emitter.onNext("Success");
} else {
emitter.onError(new RuntimeException());
}
}
})
.take(1)
.subscribeOn(Schedulers.io())
.lift(CircuitBreakerOperator.of(breaker1))
.onErrorReturn(e -> "Failure")
.blockingFirst();
System.out.println(output);
}
Metrics metrics = breaker1.getMetrics();
System.out.println(String.format("Calls = %d, BufferSize = %d, Success = %d, Failed = %d",
metrics.getNumberOfBufferedCalls(),
metrics.getMaxNumberOfBufferedCalls(),
metrics.getNumberOfSuccessfulCalls(),
metrics.getNumberOfFailedCalls()));
Result of above code: A Success event is given every time onNext() is called, and a failure event everytime onError() is called.
But now, after upgrading to 0.15.0, the code transforms as such:
CircuitBreakerConfig config = CircuitBreakerConfig.custom()
.ringBufferSizeInClosedState(10)
.ringBufferSizeInHalfOpenState(5)
.waitDurationInOpenState(Duration.ofMillis(10000))
.failureRateThreshold(0.50f)
.build();
CircuitBreaker breaker1 = CircuitBreaker.of("one", config);
breaker1.getEventPublisher()
.onEvent(r4jEvent -> System.out.println(String.format("Got an event %s for Circuit %s",
r4jEvent, breaker1)));
for (int i = 0; i < 10; i++) {
final int index = i;
String output = Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> emitter) throws Exception {
if (index % 2 == 0) {
emitter.onNext("Success");
} else {
emitter.onError(new RuntimeException());
}
}
})
.take(1)
.subscribeOn(Schedulers.io())
.compose(CircuitBreakerOperator.of(breaker1))
.onErrorReturn(e -> "Failure")
.blockingFirst();
System.out.println(output);
}
Results: Only onError() events are recorded by the event Publisher , and no Success events are recorded.
Given that .compose() is a stream level operation while .lift() is an item level one, I would expect that a potential workaround would be to ensure emitter.onComplete()
is called within the ObservableOnSubscribe.subscribe()
Issue Analytics
- State:
- Created 4 years ago
- Comments:8 (7 by maintainers)
Top Results From Across the Web
CircuitBreaker - resilience4j
In these two states no Circuit Breaker events (apart from the state transition) are generated, and no metrics are recorded. The only way...
Read more >CircuitBreakerOperator (resilience4j-rxjava2 0.14.0 API)
A RxJava operator which protects a reactive type by a CircuitBreaker. Please note that the subscribed operators might affect the circuit breaker even...
Read more >Implementing a Circuit Breaker with Resilience4j - Reflectoring
A deep dive into the Resilience4j circuit breaker module. This article shows why, when and how to use it to build resilient applications....
Read more >Issue with io.github.resilience4j version 1.7.2 ... - Stack Overflow
Everything is working fine with 1.6.1 version but when upgraded to 1.7.1 version my application is not running. Please find my code changes ......
Read more >Spring Cloud Circuit Breaker
The Spring Cloud CircuitBreaker project contains implementations for Resilience4J and Spring Retry. The APIs implemented in Spring Cloud CircuitBreaker live ...
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
I think I have a solution. The CircuitBreakerOperator could track if an event has been emitted successfully (onNext). And when
dispose
is invoked, the CircuitBreakerOperator either invokescircuitBreaker.onSuccess
orcircuitBreaker.releasePermission
.This change results in:
I think I understand it now. When the first observable is complete, the second observable is cancelled as soon as it emitted the next event. It’s because zip must combine two events. It makes no sense to consume further events of the second observable when the first is completed.
Unfortunately the cancellation is bad for the CircuitBreakerOperator. I’ve to think about how the CircuitBreakerOperator fits into this design.