io.github.resilience4j.circuitbreaker.CircuitBreaker is not thread-safe
See original GitHub issueDear all,I try it and find CircuitBreaker is not thread-safe , I see the CircuitBreaker source code :A CircuitBreaker instance is thread-safe can be used to decorate multiple requests.
my code
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;
import io.github.resilience4j.circuitbreaker.CircuitBreaker;
import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
import io.vavr.control.Try;
public class Test {
public interface BackendService {
String doSomethingWithArgs(String name);
String doSomethingThrowException ()throws Exception ;
}
static BackendService backendService = new BackendService() {
AtomicInteger id = new AtomicInteger(0);
@Override
public String doSomethingWithArgs(String s) {
System.out.println("call time :" + id.getAndIncrement());
throw new RuntimeException("bug...");
// return "success";
}
@Override
public String doSomethingThrowException() {
System.out.println("doSomethingThrowexception");
throw new RuntimeException("bug...");
}
};
static CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom().failureRateThreshold(5)
.ringBufferSizeInHalfOpenState(10).ringBufferSizeInClosedState(15)
.enableAutomaticTransitionFromOpenToHalfOpen().build();
static CircuitBreaker circuitBreaker = CircuitBreaker.of("mybreaker", circuitBreakerConfig);
public static void main(String[] args) throws InterruptedException {
ExecutorService ex = Executors.newFixedThreadPool(20);
for (int i = 0; i < 30; i++) {
ex.execute(() -> {
Supplier<String> supplier = CircuitBreaker.decorateSupplier(circuitBreaker,
() -> backendService.doSomethingWithArgs("world"));
Try.ofSupplier(supplier).onFailure(e -> {
System.out.println(circuitBreaker.getState() + "\t" + e.getMessage() + "\t"
+ circuitBreaker.getMetrics().getFailureRate());
}).onSuccess(e -> {
System.out.println(Thread.currentThread().getName() + "\t" + e);
});
});
}
ex.shutdown();
}
}
this code will print “call time 23” change Executors.newFixedThreadPool(20); to Executors.newFixedThreadPool(1); at this time print “call time 14” Thank you for you time
Issue Analytics
- State:
- Created 4 years ago
- Comments:7 (3 by maintainers)
Top Results From Across the Web
resilience4j/CircuitBreaker.java at master - GitHub
* A CircuitBreaker instance is thread-safe can be used to decorate multiple requests. * <p>. * A {@link CircuitBreaker} manages the state of...
Read more >CircuitBreaker permits more calls then expected ... - GitHub
Resilience4j version: 1.7.0 Java version: Java16 CircuitBreaker permits more calls then expected when switching from OPEN to HALF_OPEN state ...
Read more >ConcurrentModificationException warning log while ... - GitHub
Hi, I seems that some code is adding an another event consumer while the event consumer list of the CircuitBreaker is in use?...
Read more >resilience4j/CircuitBreakerStateMachine.java at master - GitHub
Resilience4j is a fault tolerance library designed for Java8 and functional programming - resilience4j/CircuitBreakerStateMachine.java at master ...
Read more >Document thread-safety of resilience4j primitives #137 - GitHub
CircuitBreaker, RateLimiter and Bulkhead can be used for multiple requests and can be shared, because they are thread-safe.
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
@RobWin @storozhukBM Thanks again. Let me think about it .
@RobWin thank you for answers above. I found them fully reasonable and descriptive. But maybe we encounter this problem because of our common knowledge of the low level circuit breaker API and architecture, that is not typically known for our users. @srchen1987 thank you also for this question. I understand your problem and behavior that you want to achieve. Unfortunately, the thing that you are asking is not possible from a physics standpoint, because it demands the prediction of future events, which is not achievable. I’ll do my best to describe the actual situation that you faced, but please fill free to ask any additional questions. As you understand, the circuit breaker is a thread-safe data structure that collects information about already happened events that are results of a particular action and exposes its opinion about the safety of performing the same action in the current moment. So let us use sequence diagrams to see what happened in the case of a single thread in your pool:
As you can see with a single thread, everything is simple because all operations are sequential. But in multithreaded mode, everything is a lot more complicated:
In your case with 20 threads, circuit breaker gives you 20 permissions because no error happened at this given point of time and even after a first cycle some threads actually managed to get more permissions before all others registered their failures from the previous cycle.
Hopefully, these diagrams will help you understand that behavior that you see is expected, and the only way you can deal with would be some sort of concurrency restrictions as bulkhead or rate limiter.
I can also recommend my article about circuit breaker implementation details that can help with the understanding of its capabilities https://medium.com/@storozhuk.b.m/circuit-breaker-implementation-in-resilience4j-992af908c413