-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CircuitBreaker: unhandled exceptions can count as the single attempt permitted in half-open state #311
Comments
@brunoabreu . That's a great question. It should not be the case. The circuit-breaker engine explicitly rethrows unhandled execptions ( I was able to construct a quick test, showing that the unhandled exception leaves the circuit in half-open state: [Fact]
public void Should_leave_circuit_halfopen_if_the_next_call_raises_an_unhandled_exception()
{
var time = 1.January(2000);
SystemClock.UtcNow = () => time;
var durationOfBreak = TimeSpan.FromMinutes(1);
CircuitBreakerPolicy breaker = Policy
.Handle<DivideByZeroException>()
.CircuitBreaker(2, durationOfBreak);
breaker.Invoking(x => x.RaiseException<DivideByZeroException>())
.ShouldThrow<DivideByZeroException>();
breaker.CircuitState.Should().Be(CircuitState.Closed);
breaker.Invoking(x => x.RaiseException<DivideByZeroException>())
.ShouldThrow<DivideByZeroException>();
breaker.CircuitState.Should().Be(CircuitState.Open);
// 2 exception raised, circuit is now open
breaker.Invoking(x => x.RaiseException<DivideByZeroException>())
.ShouldThrow<BrokenCircuitException>();
breaker.CircuitState.Should().Be(CircuitState.Open);
// duration has passed, circuit now half open
SystemClock.UtcNow = () => time.Add(durationOfBreak);
breaker.CircuitState.Should().Be(CircuitState.HalfOpen);
// first call after duration raises an unhandled exception
breaker.Invoking(x => x.RaiseException<TaskCanceledException>())
.ShouldThrow<TaskCanceledException>();
// unhandled exception should not affect state - breaker should still be halfopen
breaker.CircuitState.Should().Be(CircuitState.HalfOpen);
} Could what you are seeing be that the circuit-breaker only permits one execution attempt per So: If, after the first Does that sound like it describes your scenario? There are tests showing this here. Adding the following lines to the end of the test above, also demonstrate this:
The behaviour is by design, to prevent request stampedes during half-open state, and matches Hystrix's approach. If that doesn't describe your scenario (or if qs about it), let me know, and we'll dig deeper. |
@reisenberger thank you for your explanation. I wasn't aware of this single trial call per Although I understand this strategy, it seems a little odd because if I'm not handling some kind of exception and it happens, I don't expect it to be treated as a failure that prevents my circuit breaker from transitioning If it is |
@reisenberger Quick question. I am facing similar issue. When the circuit is in open state and transistioned to half open and at the same time if we get two calls, are we saying that we allow only one call to pass through and other call will get Broken Circuit Exception? I am seeing similar behavior. If that's case, can we skip whole half-open? :) |
@pvmraghunandan Quick answers:
Yes, as documented in the circuit-breaker wiki. I've made the doco clearer to confirm that blocked executions in half-open also throw
No built-in Polly syntax to do that. But you could achieve it by configuring the We may later introduce an injectible circuit-breaker controller you could custom-code to control circuit-breaker behaviour more finely. |
onHalfOpen delegate doesn't have context. How to you propose to use context to pass in breakerPolicy to be reset in onHalfOpen? |
@amiyaaloke You are correct: apologies for getting that wrong. In that case, the approach outlined above is not achievable with current Polly. I remember now also why As part of #287 we intend to introduce an injectible |
@reisenberger thanks for the explanation. As a workaround I added code to cache policy registry and onHalfOpen callback reset the circuit breakers that are on HalfOpen state to close the circuit. Let me know if you see any downside of this approach. |
@amiyaaloke Sounds to me like that should work 👍 |
@reisenberger Yes. this seems to working well with lock in place to make it thread safe. Thanks for reply 👍 |
Closing due to no further comments on the original issue in a couple of years. |
I'm using a CircuitBreaker to wrap some HTTP calls.
My HTTP client has a timeout and sometimes it throws a TaskCanceledException.
I'm not handling that exception on my CircuitBreaker and it works fine, not transitioning from
closed
toopen
state when a timeout happens. But when the circuit ishalf-open
, that exception prevents it to beclosed
.It seems like any exception thrown during
half-open
state, handled or not, opens the circuit.Is that an expected behavior?
The text was updated successfully, but these errors were encountered: