question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

io.github.resilience4j.circuitbreaker.CircuitBreaker is not thread-safe

See original GitHub issue

Dear 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:closed
  • Created 4 years ago
  • Comments:7 (3 by maintainers)

github_iconTop GitHub Comments

3reactions
srchen1987commented, May 22, 2019

@RobWin @storozhukBM Thanks again. Let me think about it .

3reactions
storozhukBMcommented, May 22, 2019

@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:

Screen Shot 2019-05-22 at 1 28 34 PM

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:

Screen Shot 2019-05-22 at 1 58 37 PM

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

Read more comments on GitHub >

github_iconTop 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 >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found