Skip to content
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's Open state should return a faulted Task instead of throwing #5117

Closed
ismaelhamed opened this issue Jul 1, 2021 · 5 comments · Fixed by #5150
Closed

CircuitBreaker's Open state should return a faulted Task instead of throwing #5117

ismaelhamed opened this issue Jul 1, 2021 · 5 comments · Fixed by #5150

Comments

@ismaelhamed
Copy link
Member

Version Information
Akka 1.4.21

Describe the bug
CircuitBreaker's Open and HalfOpen states should return a faulted Task with the OpenCircuitException exception instead of throwing.

To Reproduce

circuitBreaker.WithCircuitBreaker(dangerousAsyncOperation)
    .PipeTo(Self, failure: exception => new Success.Failure(exception));

Expected behavior
Be able to handle the OpenCircuitException with just the PipeTo, without needing to add another ContinueWith to the mix.

Actual behavior
OpenCircuitException cannot be handled in the failure callback, and the actor restarts due to the unhadled exception.

Proposed fix
Return a faulted Task:

public override Task Invoke(Func<Task> body) => Task.FromException(
    new OpenCircuitException(_breaker.LastCaughtException, RemainingDuration()));

...instead of throwing

public override Task Invoke(Func<Task> body) =>
    throw new OpenCircuitException(_breaker.LastCaughtException, RemainingDuration());
@ismaelhamed ismaelhamed changed the title CircuitBreaker's Open and HalfOpen invoke functions should return a faulted Task instead of throwing CircuitBreaker's Open and HalfOpen states should return a faulted Task instead of throwing Jul 1, 2021
@Aaronontheweb Aaronontheweb added this to the 1.4.22 milestone Jul 1, 2021
@Aaronontheweb
Copy link
Member

Agree - do we need to break the existing API in order to do this?

@ismaelhamed
Copy link
Member Author

ismaelhamed commented Jul 2, 2021

Not the API, but if someone is wrapping the calls to the CB in a try... catch (for whatever reason), that won't work anymore. I couldn't find anything like that in our code base except for this piece in the SnapshotStore:

try
{
    ReceivePluginInternal(message);
    _breaker.WithCircuitBreaker(() => DeleteAsync(saveSnapshotFailure.Metadata));
}
finally
{
    senderPersistentActor.Tell(message);
}

But I don't think the intent was to shield against any exception throwing in the CB but in the call to ReceivePluginInternal. In fact, here is the same code in scala, and AFAIK you cannot catch exceptions wrapped in a Future with a try... catch either.

@ismaelhamed
Copy link
Member Author

@Aaronontheweb any thoughts?

@Aaronontheweb
Copy link
Member

Looks good to me - let's go for it.

@Aaronontheweb
Copy link
Member

Sorry for the delay on getting back to you on this @ismaelhamed - this change looks safe.

@ismaelhamed ismaelhamed changed the title CircuitBreaker's Open and HalfOpen states should return a faulted Task instead of throwing CircuitBreaker's Open state should return a faulted Task instead of throwing Jul 19, 2021
This was referenced Aug 5, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants