-
-
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
Polly V8: Public API Review #1233
Conversation
Codecov Report
@@ Coverage Diff @@
## main #1233 +/- ##
=======================================
Coverage 83.59% 83.59%
=======================================
Files 268 268
Lines 6377 6377
Branches 1007 1007
=======================================
Hits 5331 5331
Misses 837 837
Partials 209 209
Flags with carried forward coverage won't be shown. Click here to find out more. |
I think all non-generic variants must be nuked and we should work through the model of how to use generic flavors of policies to support all possible cases |
I am transferring some comments from internal review to public so these will be visible by broader audience. |
ApiReview/API.Polly.Core/NoDocs/Polly.Registry/ResilienceStrategyRegistryOptions.cs
Outdated
Show resolved
Hide resolved
ApiReview/API.Polly.Core/NoDocs/Polly.Retry/RetryBackoffType.cs
Outdated
Show resolved
Hide resolved
ApiReview/API.Polly.Core/NoDocs/Polly.Strategy/Outcome.TResult.cs
Outdated
Show resolved
Hide resolved
ApiReview/API.Polly.Core/NoDocs/Polly.Strategy/PredicateResult.cs
Outdated
Show resolved
Hide resolved
ApiReview/API.Polly.Core/NoDocs/Polly.Strategy/ResilienceStrategyOptions.cs
Outdated
Show resolved
Hide resolved
ApiReview/API.Polly.Core/NoDocs/Polly/ResilienceStrategyBuilder.TResult.cs
Outdated
Show resolved
Hide resolved
ApiReview/API.Polly.Core/NoDocs/Polly/ResilienceStrategyBuilder.cs
Outdated
Show resolved
Hide resolved
...Polly.Extensions/NoDocs/Polly.Extensions.DependencyInjection/PollyDependencyInjectionKeys.cs
Outdated
Show resolved
Hide resolved
...API.Polly.Extensions/NoDocs/Polly.Extensions.Telemetry/TelemetryResilienceStrategyOptions.cs
Outdated
Show resolved
Hide resolved
ApiReview/API.Polly.RateLimiting/NoDocs/Polly/RateLimiterResilienceStrategyBuilderExtensions.cs
Outdated
Show resolved
Hide resolved
ApiReview/API.Polly.Core/NoDocs/Polly/CircuitBreakerResilienceStrategyBuilderExtensions.cs
Outdated
Show resolved
Hide resolved
ApiReview/API.Polly.Core/NoDocs/Polly.Strategy/IResilienceArguments.cs
Outdated
Show resolved
Hide resolved
ApiReview/API.Polly.Core/NoDocs/Polly.Strategy/PredicateBuilder.cs
Outdated
Show resolved
Hide resolved
ApiReview/API.Polly.Core/NoDocs/Polly.Strategy/PredicateBuilder.cs
Outdated
Show resolved
Hide resolved
ApiReview/API.Polly.Core/NoDocs/Polly.Strategy/ResilienceStrategyOptions.cs
Outdated
Show resolved
Hide resolved
ApiReview/API.Polly.Core/NoDocs/Polly.Timeout/TimeoutRejectedException.cs
Show resolved
Hide resolved
.../API.Polly.Core/NoDocs/Polly.CircuitBreaker/AdvancedCircuitBreakerStrategyOptions.TResult.cs
Outdated
Show resolved
Hide resolved
ApiReview/API.Polly.Core/NoDocs/Polly.Retry/RetryStrategyOptions.cs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You know, if you introduced a type such as Nothing (a struct with no state), you could eliminate a ton of APIs and code throughout. You'd only need to keep the generic version of everything, and if the case at hand has no state, then you'd use something like Outcome.
This is a recognized flaw in the CLR's generic system, it should have allowed to use 'void' as a generic type parameter, but it doesn't. But using Nothing achieves the same effect.
...tensions/NoDocs/Microsoft.Extensions.DependencyInjection/PollyServiceCollectionExtensions.cs
Outdated
Show resolved
Hide resolved
ApiReview/API.Polly.RateLimiting/NoDocs/Polly.RateLimiting/RateLimiterStrategyOptions.cs
Outdated
Show resolved
Hide resolved
ApiReview/API.Polly.Core/NoDocs/Polly.Retry/RetryStrategyOptions.cs
Outdated
Show resolved
Hide resolved
ApiReview/API.Polly.Core/NoDocs/Polly.Timeout/TimeoutStrategyOptions.cs
Outdated
Show resolved
Hide resolved
The non-generic policies are not about void results. These are used in scenarios where the consumer only cares about exceptions. This way, they can use a single policy across their entire stack and do not care about handling each individual result type. Actually, in my previous work we did not use generic policies at all, as everything was handled using domain-specific exceptions. @joelhulen or @martincostello can hopefully provide more details. |
[Required] | ||
public ConcurrencyLimiterOptions DefaultRateLimiterOptions { get; set; } | ||
public Func<OnRateLimiterRejectedArguments, ValueTask>? OnRejected { get; set; } | ||
public ResilienceRateLimiter? RateLimiter { get; set; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
public ResilienceRateLimiter? RateLimiter { get; set; } | |
public Func<ValueTask<RateLimitLease>, ResilienceContext> RateLimiter { get; set; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you meant:
public Func<ResilienceContext, ValueTask<RateLimitLease>> RateLimiter { get; set; }
Looks good, but we would have to solve the problem with resource management i.e. disposing unused rate limiters after pipeline is reloaded.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Give this a shot.
ApiReview/API.Polly.RateLimiting/NoDocs/Polly.RateLimiting/OnRateLimiterRejectedArguments.cs
Show resolved
Hide resolved
public class TimeoutStrategyOptions : ResilienceStrategyOptions | ||
{ | ||
[Range(typeof(TimeSpan), "00:00:01", "1.00:00:00")] | ||
public TimeSpan Timeout { get; set; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this a good name?
public TimeSpan Timeout { get; set; } | |
public TimeSpan DefaultTimeout { get; set; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am 50/50 on both.
|
||
public readonly struct OnTimeoutArguments | ||
{ | ||
public ResilienceContext Context { get; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there is no consistency across various On*Arguments types on whether ResilienceContext
should be included in the args or not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Context
property is on all outcome-less arguments. All outcome-based delegates use OutcomeArguments
that enforces the ResilienceContext
and Outcome
on construction.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's try to get rid of OutcomeArguments
public TResult? Result { get; } | ||
public bool HasResult { get; } | ||
public bool IsVoidResult { get; } | ||
public void EnsureSuccess(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would expect Result
getter to throw an exception if there was an exception.
similar to how Task.Result throws a captured exception.
but is this method even needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should avoid throwing exceptions from Outcome
as it is low-level API used in high-perf scenarios and in delegates.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is similar pattern that's used for HttpResponseMessage
to check for successful status code. Also Cosmos DB SDK has similar implementation - you either work with DTOs directly (higher level) and get the exceptions, or you work with ResponseMessage
(lower level) but need to check for the result explicitly using response.EnsureSuccessStatusCode()
.
ApiReview/API.Polly.Core/NoDocs/Polly.Hedging/HedgingActionGeneratorArguments.cs
Show resolved
Hide resolved
Closing in favor of #1507 |
@martincostello, closed this one and opened #1507 with remaining comments transferred there. |
Details on the issue fix or feature implementation
Great news! We've been working hard and we're excited to finally introduce Polly V8 for public API review. The purpose of this PR is to outline the API signatures in the upcoming release. We welcome your comments, suggestions, and improvements to refine the API. Once we reach a consensus on the outcome, we will move forward to publish alpha packages for V8.
Summary of Changes
In the following table, we provide a comparison between V7 and V8:
IAsyncPolicy
ResiliencePipeline
ResiliencePipeline
can be utilized in both synchronous and asynchronous scenarios.ISyncPolicy
ResiliencePipeline
ResiliencePipeline
can be utilized in both synchronous and asynchronous scenarios.IAsyncPolicy<T>
ResiliencePipeline<T>
ResiliencePipeline<T>
can be utilized in both synchronous and asynchronous scenarios.ISyncPolicy<T>
ResiliencePipeline<T>
ResiliencePipeline<T>
can be utilized in both synchronous and asynchronous scenarios.Context
ResilienceContext
Policy
ResiliencePipelineBuilder
Policy
ResiliencePipelineBuilder<T>
Building
ResiliencePipeline<TResult>
that handles single type of the resultBelow is an example of how to create a
ResiliencePipeline<HttpResponseMessage>
using convenience API:In addition, for maximum flexibility, you can utilize options as shown below:
Building
ResiliencePipeline
that handles any type of the resultFor scenarios where the caller does not care about the results and only need exception handling, the non-generic resilience strategy can be used:
Performance
Polly V8 is FAST. We have 70x less allocations and ~20% faster execution compared to V7. Actually, most V8 strategies have zero allocations.
See our benchmark results:
https://github.com/App-vNext/Polly/tree/main/bench/BenchmarkDotNet.Artifacts/results
For more detailed information on the architecture of Polly V8, please refer to the README.md in the
Polly.Core
directory.