[Docs] Add circuit breaker to the migration guide#1764
[Docs] Add circuit breaker to the migration guide#1764martincostello merged 14 commits intoApp-vNext:mainfrom
Conversation
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #1764 +/- ##
=======================================
Coverage 84.53% 84.53%
=======================================
Files 307 307
Lines 6777 6777
Branches 1043 1043
=======================================
Hits 5729 5729
Misses 839 839
Partials 209 209
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
I think we should keep it for the reasons you mentioned - note that v8 does not have it anymore.
I think this is fine, another alternative is to use the low-allocation |
I think it might make sense to mention this case on the migration guide and provide a link to the related anti-pattern section where we detail the solution. Do you agree? |
I try to put together the suggested way but it feels a bit clumsy for me. The anti-pattern var stateProvider = new CircuitBreakerStateProvider();
var circuitBreaker = new ResiliencePipelineBuilder()
.AddCircuitBreaker(new()
{
ShouldHandle = new PredicateBuilder().Handle<HttpRequestException>(),
BreakDuration = TimeSpan.FromSeconds(0.5),
StateProvider = stateProvider
})
.Build();
if (stateProvider.CircuitState
is not CircuitState.Open
and not CircuitState.Isolated)
{
await circuitBreaker.ExecuteAsync(static ct =>
{
// Your code goes here
return default;
}, CancellationToken.None);
}The pattern var context = ResilienceContextPool.Shared.Get();
var circuitBreaker = new ResiliencePipelineBuilder()
.AddCircuitBreaker(new()
{
ShouldHandle = new PredicateBuilder().Handle<HttpRequestException>(),
BreakDuration = TimeSpan.FromSeconds(0.5),
})
.Build();
Outcome<bool> result = await circuitBreaker.ExecuteOutcomeAsync(static (ctx, state) =>
{
// Your code goes here
return Outcome.FromResultAsValueTask(true);
}, context, "state");
ResilienceContextPool.Shared.Return(context);Using Outcome<object?> result = await circuitBreaker.ExecuteOutcomeAsync(static (ctx, state) =>
{
// Your code goes here
return Outcome.FromResultAsValueTask<object?>(null);
}, context, "state");@martintmk Do you have any other alternative which feels more natural? |
|
The main idea is to just execute the callback as one normally would and afterwards one can check the result. For example: Outcome<bool> result = await circuitBreaker.ExecuteOutcomeAsync(static (ctx, state) => ... );
if (result.Exception is BrokenCircuitException)
{
// the execution was stopped by CB
}
else
{
// the callback was executed and passed through CB
} |
|
@martintmk Yeah I do understand that part. Let me try to rephrase my problem. There is no non-generic If there were a non-generic Outcome result = await circuitBreaker.ExecuteOutcomeAsync(static (ctx, state) =>
{
// Your code goes here
return ValueTask.FromResult(new Outcome());
}, context, "state");Anyway maybe overthinking and it is the same problem as with the |
You are right, there is currently no way to return "void outcome", you need to use workaround you mentioned above. Still, this is for more advanced scenarios so I would wait for feedback until someone really complains :) |
In this case I will use |
This reverts commit db0765b.
Co-authored-by: Martin Costello <martin@martincostello.com>
Pull Request
The issue or feature being addressed
Details on the issue fix or feature implementation
Migration.CircuitBreaker.csfile with V7 and V8 samplesmigration-v8.mdfilesOpen questions
Answer: keep it under the V7 paragraph
Answer: add it to the anti-patterns section and add reference to that from the migration guide
Confirm the following