From a0be5612f1144ed13278b14b7e7e0b72071ab617 Mon Sep 17 00:00:00 2001 From: Martin Costello Date: Wed, 30 Aug 2023 14:04:58 +0100 Subject: [PATCH] Updates for alpha.9 (#1526) - Update CHANGELOG. - Bump samples to 8.0.0-alpha.9. --- CHANGELOG.md | 44 ++++++++++++++++++++++++++ Directory.Packages.props | 2 +- README.md | 4 +-- samples/DependencyInjection/Program.cs | 32 +++++++++---------- samples/Extensibility/Program.cs | 33 ++++++++----------- samples/GenericStrategies/Program.cs | 38 ++++++++++++++-------- samples/Intro/Program.cs | 36 +++++++++++---------- samples/Retries/Program.cs | 41 ++++++++++++------------ 8 files changed, 143 insertions(+), 87 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cc3e56adda..8550acc693 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,47 @@ +## 8.0.0-alpha.9 + +* Updates for alpha.8 by [@martincostello](https://github.com/martincostello) in https://github.com/App-vNext/Polly/pull/1465 +* Fix unstable build by [@martintmk](https://github.com/martintmk) in https://github.com/App-vNext/Polly/pull/1466 +* Improve samples by [@martintmk](https://github.com/martintmk) in https://github.com/App-vNext/Polly/pull/1467 +* Specify DebuggerDisplay for ReactiveResilienceStrategyBridge by [@martintmk](https://github.com/martintmk) in https://github.com/App-vNext/Polly/pull/1468 +* Drop the `Extensions` from `Polly.Extensions` namespace by [@martintmk](https://github.com/martintmk) in https://github.com/App-vNext/Polly/pull/1469 +* Remove Moq by [@martincostello](https://github.com/martincostello) in https://github.com/App-vNext/Polly/pull/1472 +* Add new metering tests to cover uncovered lines by [@martintmk](https://github.com/martintmk) in https://github.com/App-vNext/Polly/pull/1474 +* Default names for individual resilience strategies by [@martintmk](https://github.com/martintmk) in https://github.com/App-vNext/Polly/pull/1475 +* Introduce `NonReactiveResilienceStrategy` by [@martintmk](https://github.com/martintmk) in https://github.com/App-vNext/Polly/pull/1476 +* Drop `TelemetryResilienceStrategy` by [@martintmk](https://github.com/martintmk) in https://github.com/App-vNext/Polly/pull/1482 +* API Review feedback (1) by [@martintmk](https://github.com/martintmk) in https://github.com/App-vNext/Polly/pull/1484 +* Rename ResilienceStrategy to ResiliencePipeline by [@martintmk](https://github.com/martintmk) in https://github.com/App-vNext/Polly/pull/1483 +* API Review Feedback (2) by [@martintmk](https://github.com/martintmk) in https://github.com/App-vNext/Polly/pull/1485 +* Introduce TelemetryListener by [@martintmk](https://github.com/martintmk) in https://github.com/App-vNext/Polly/pull/1486 +* Improve documentation by [@martintmk](https://github.com/martintmk) in https://github.com/App-vNext/Polly/pull/1487 +* Fix metering tests by [@martintmk](https://github.com/martintmk) in https://github.com/App-vNext/Polly/pull/1488 +* Hide validation APIs by [@martintmk](https://github.com/martintmk) in https://github.com/App-vNext/Polly/pull/1490 +* Logging improvements by [@martintmk](https://github.com/martintmk) in https://github.com/App-vNext/Polly/pull/1489 +* Hide/drop some unused APIs by [@martintmk](https://github.com/martintmk) in https://github.com/App-vNext/Polly/pull/1491 +* Cleanup internals by [@martintmk](https://github.com/martintmk) in https://github.com/App-vNext/Polly/pull/1492 +* ResilienceContextPool improvements by [@martintmk](https://github.com/martintmk) in https://github.com/App-vNext/Polly/pull/1493 +* Hide IsSynchronous property by [@martintmk](https://github.com/martintmk) in https://github.com/App-vNext/Polly/pull/1494 +* Drop unused ResiliencePipelineRegistry APIs by [@martintmk](https://github.com/martintmk) in https://github.com/App-vNext/Polly/pull/1495 +* `ResiliencePipelineRegistry` is now disposable by [@martintmk](https://github.com/martintmk) in https://github.com/App-vNext/Polly/pull/1496 +* Move pipeline-related internals into `Pipeline` folder by [@martintmk](https://github.com/martintmk) in https://github.com/App-vNext/Polly/pull/1497 +* Update benchmarks by [@martintmk](https://github.com/martintmk) in https://github.com/App-vNext/Polly/pull/1503 +* Minor ResiliencePipelineRegistry cleanup of internals by [@martintmk](https://github.com/martintmk) in https://github.com/App-vNext/Polly/pull/1505 +* API Review Feedback by [@martintmk](https://github.com/martintmk) in https://github.com/App-vNext/Polly/pull/1506 +* Minor API cleanup by [@martintmk](https://github.com/martintmk) in https://github.com/App-vNext/Polly/pull/1508 +* Clenaup rate limiter API by [@martintmk](https://github.com/martintmk) in https://github.com/App-vNext/Polly/pull/1509 +* Cleanup ResiliencePipelineRegistry internals by [@martintmk](https://github.com/martintmk) in https://github.com/App-vNext/Polly/pull/1510 +* Allow to dispose linked resources on pipeline disposal by [@martintmk](https://github.com/martintmk) in https://github.com/App-vNext/Polly/pull/1511 +* Simplify and enhance the pipeline reloads by [@martintmk](https://github.com/martintmk) in https://github.com/App-vNext/Polly/pull/1512 +* Drop `OutcomeArguments` struct by [@martintmk](https://github.com/martintmk) in https://github.com/App-vNext/Polly/pull/1513 +* API Review Feedback by [@martintmk](https://github.com/martintmk) in https://github.com/App-vNext/Polly/pull/1520 +* Got rid of some warnings in the Polly project by [@IgorIgorevich94](https://github.com/IgorIgorevich94) in https://github.com/App-vNext/Polly/pull/1514 +* API Review Feedback by [@martintmk](https://github.com/martintmk) in https://github.com/App-vNext/Polly/pull/1521 +* Cleanup Outcome internals and drop unused hedging and fallbacks APIs by [@martintmk](https://github.com/martintmk) in https://github.com/App-vNext/Polly/pull/1523 +* Improve debugging experience for `ResilienceProperties` by [@martintmk](https://github.com/martintmk) in https://github.com/App-vNext/Polly/pull/1524 +* Protect against retry delay overflows by [@martintmk](https://github.com/martintmk) in https://github.com/App-vNext/Polly/pull/1522 +* Fix DelayAsync extension by [@martintmk](https://github.com/martintmk) in https://github.com/App-vNext/Polly/pull/1525 + ## 8.0.0-alpha.8 * Updates for 8.0.0-alpha.7 by [@martincostello](https://github.com/martincostello) in https://github.com/App-vNext/Polly/pull/1433 diff --git a/Directory.Packages.props b/Directory.Packages.props index becfb7816f..972fb254aa 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -2,7 +2,7 @@ 7.0.0 true - 8.0.0-alpha.8 + 8.0.0-alpha.9 diff --git a/README.md b/README.md index 8ea9e29ed8..e59e6f9d57 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,8 @@ > Major performance improvements are on the way! Please see our [blog post](https://www.thepollyproject.org/2023/03/03/we-want-your-feedback-introducing-polly-v8/) to learn more and provide feedback in the [related GitHub issue](https://github.com/App-vNext/Polly/issues/1048). > > :rotating_light::rotating_light: **Polly v8 feature-complete!** :rotating_light::rotating_light: -> - Polly v8 Alpha 8 is now available on [NuGet.org](https://www.nuget.org/packages/Polly/8.0.0-alpha.8) -> - The Alpha 8 version is considered feature-complete. After completing [review of the API](https://github.com/App-vNext/Polly/pull/1233) to address unresolved issues, we will move on to a Beta release. +> - Polly v8 Alpha 9 is now available on [NuGet.org](https://www.nuget.org/packages/Polly/8.0.0-alpha.9) +> - The Alpha 9 version is considered feature-complete. After completing [review of the API](https://github.com/App-vNext/Polly/pull/1233) to address unresolved issues, we will move on to a Beta release. > - The v8 docs are not yet finished, but you can take a look at sample code in these locations: > - Within the repo's new [Samples folder](https://github.com/App-vNext/Polly/tree/main/samples) > - By reading `Polly.Core`'s [README](https://github.com/App-vNext/Polly/blob/main/src/Polly.Core/README.md) diff --git a/samples/DependencyInjection/Program.cs b/samples/DependencyInjection/Program.cs index 9a269514cd..4e1ead5feb 100644 --- a/samples/DependencyInjection/Program.cs +++ b/samples/DependencyInjection/Program.cs @@ -5,49 +5,49 @@ using Polly.Timeout; // ------------------------------------------------------------------------ -// 1. Register your resilience strategy +// 1. Register your resilience pipeline // ------------------------------------------------------------------------ var serviceProvider = new ServiceCollection() .AddLogging(builder => builder.AddConsole().SetMinimumLevel(LogLevel.Debug)) - // Use "AddResilienceStrategy" extension method to configure your named strategy - .AddResilienceStrategy("my-strategy", (builder, context) => + // Use "AddResiliencePipeline" extension method to configure your named pipeline + .AddResiliencePipeline("my-pipeline", (builder, context) => { - // You can resolve any service from DI when building the strategy + // You can resolve any service from DI when building the pipeline context.ServiceProvider.GetRequiredService(); builder.AddTimeout(TimeSpan.FromSeconds(1)); }) - // You can also register result-based (generic) resilience strategies + // You can also register result-based (generic) resilience pipelines // First generic parameter is the key type, the second one is the result type // This overload does not use the context argument (simple scenarios) - .AddResilienceStrategy("my-http-strategy", builder => + .AddResiliencePipeline("my-http-pipeline", builder => { builder.AddTimeout(TimeSpan.FromSeconds(1)); }) .BuildServiceProvider(); // ------------------------------------------------------------------------ -// 2. Retrieve and use your resilience strategy +// 2. Retrieve and use your resilience pipeline // ------------------------------------------------------------------------ -// Resolve the resilience strategy provider for string-based keys -ResilienceStrategyProvider strategyProvider = serviceProvider.GetRequiredService>(); +// Resolve the resilience pipeline provider for string-based keys +ResiliencePipelineProvider pipelineProvider = serviceProvider.GetRequiredService>(); -// Retrieve the strategy by name -ResilienceStrategy strategy = strategyProvider.GetStrategy("my-strategy"); +// Retrieve the pipeline by name +ResiliencePipeline pipeline = pipelineProvider.GetPipeline("my-pipeline"); -// Retrieve the generic strategy by name -ResilienceStrategy genericStrategy = strategyProvider.GetStrategy("my-http-strategy"); +// Retrieve the generic pipeline by name +ResiliencePipeline genericPipeline = pipelineProvider.GetPipeline("my-http-pipeline"); try { - // Execute the strategy + // Execute the pipeline // Notice in console output that telemetry is automatically enabled - await strategy.ExecuteAsync(async token => await Task.Delay(10000, token), CancellationToken.None); + await pipeline.ExecuteAsync(async token => await Task.Delay(10000, token), CancellationToken.None); } catch (TimeoutRejectedException) { - // The timeout strategy cancels the user callback and throws this exception + // The timeout pipeline cancels the user callback and throws this exception Console.WriteLine("Timeout!"); } diff --git a/samples/Extensibility/Program.cs b/samples/Extensibility/Program.cs index 5ae6238197..e0cc969c91 100644 --- a/samples/Extensibility/Program.cs +++ b/samples/Extensibility/Program.cs @@ -4,9 +4,9 @@ // ------------------------------------------------------------------------ // Usage of custom strategy // ------------------------------------------------------------------------ -var strategy = new CompositeStrategyBuilder() +var pipeline = new ResiliencePipelineBuilder() // This is custom extension defined in this sample - .AddMyResilienceStrategy(new MyResilienceStrategyOptions + .AddMyResilienceStrategy(new MySimpleStrategyOptions { OnCustomEvent = args => { @@ -16,20 +16,20 @@ }) .Build(); -// Execute the strategy -strategy.Execute(() => { }); +// Execute the pipeline +pipeline.Execute(() => { }); // ------------------------------------------------------------------------ // SIMPLE EXTENSIBILITY MODEL (INLINE STRATEGY) // ------------------------------------------------------------------------ -strategy = new CompositeStrategyBuilder() +pipeline = new ResiliencePipelineBuilder() // Just add the strategy instance directly - .AddStrategy(new MySimpleStrategy()) + .AddStrategy(_ => new MySimpleStrategy(), new MySimpleStrategyOptions()) .Build(); -// Execute the strategy -strategy.Execute(() => { }); +// Execute the pipeline +pipeline.Execute(() => { }); internal class MySimpleStrategy : ResilienceStrategy { @@ -40,11 +40,6 @@ protected override ValueTask> ExecuteCore( { Console.WriteLine("MySimpleStrategy executing!"); - // The "context" holds information about execution mode - Console.WriteLine("context.IsSynchronous: {0}", context.IsSynchronous); - Console.WriteLine("context.ResultType: {0}", context.ResultType); - Console.WriteLine("context.IsVoid: {0}", context.IsVoid); - // The "state" is an ambient value passed by the caller that holds the state. // Here, we do not do anything with it, just pass it to the callback. @@ -65,7 +60,7 @@ protected override ValueTask> ExecuteCore( public readonly record struct OnCustomEventArguments(ResilienceContext Context); // 1.B Define the options. -public class MyResilienceStrategyOptions : ResilienceStrategyOptions +public class MySimpleStrategyOptions : ResilienceStrategyOptions { // Use the arguments in the delegates. // The recommendation is to use asynchronous delegates. @@ -79,13 +74,13 @@ public class MyResilienceStrategyOptions : ResilienceStrategyOptions // The strategy should be internal and not exposed as part of any public API. // Instead, expose options and extensions for resilience strategy builder. // -// For reactive startegies, you can use ReactiveResilienceStrategy as base class. +// For reactive strategies, you can use ReactiveResilienceStrategy as base class. internal class MyResilienceStrategy : ResilienceStrategy { private readonly ResilienceStrategyTelemetry telemetry; private readonly Func? onCustomEvent; - public MyResilienceStrategy(ResilienceStrategyTelemetry telemetry, MyResilienceStrategyOptions options) + public MyResilienceStrategy(ResilienceStrategyTelemetry telemetry, MySimpleStrategyOptions options) { this.telemetry = telemetry; this.onCustomEvent = options.OnCustomEvent; @@ -122,13 +117,13 @@ protected override async ValueTask> ExecuteCore" - public static TBuilder AddMyResilienceStrategy(this TBuilder builder, MyResilienceStrategyOptions options) where TBuilder : CompositeStrategyBuilderBase + // Add new extension that works for both "ResiliencePipelineBuilder" and "ResiliencePipelineBuilder" + public static TBuilder AddMyResilienceStrategy(this TBuilder builder, MySimpleStrategyOptions options) where TBuilder : ResiliencePipelineBuilderBase => builder.AddStrategy( // Provide a factory that creates the strategy context => new MyResilienceStrategy(context.Telemetry, options), diff --git a/samples/GenericStrategies/Program.cs b/samples/GenericStrategies/Program.cs index 8ee7edcd29..1c35402b9a 100644 --- a/samples/GenericStrategies/Program.cs +++ b/samples/GenericStrategies/Program.cs @@ -1,17 +1,17 @@ -using Polly; +using System.Net; +using Polly; using Polly.Fallback; using Polly.Retry; using Polly.Timeout; -using System.Net; // ---------------------------------------------------------------------------- -// Create a generic resilience strategy using CompositeStrategyBuilder +// Create a generic resilience pipeline using ResiliencePipelineBuilder // ---------------------------------------------------------------------------- -// The generic CompositeStrategyBuilder creates a ResilienceStrategy +// The generic ResiliencePipelineBuilder creates a ResiliencePipeline // that can execute synchronous and asynchronous callbacks that return T. -ResilienceStrategy strategy = new CompositeStrategyBuilder() +ResiliencePipeline pipeline = new ResiliencePipelineBuilder() .AddFallback(new FallbackStrategyOptions { FallbackAction = _ => @@ -20,14 +20,18 @@ return Outcome.FromResultAsTask(new HttpResponseMessage(HttpStatusCode.OK)); }, // You can also use switch expressions for succinct syntax - ShouldHandle = outcome => outcome switch + ShouldHandle = arguments => arguments.Outcome switch { // The "PredicateResult.True" is shorthand to "new ValueTask(true)" { Exception: HttpRequestException } => PredicateResult.True, { Result: HttpResponseMessage response } when response.StatusCode == HttpStatusCode.InternalServerError => PredicateResult.True, _ => PredicateResult.False }, - OnFallback = _ => { Console.WriteLine("Fallback!"); return default; } + OnFallback = _ => + { + Console.WriteLine("Fallback!"); + return default; + } }) .AddRetry(new RetryStrategyOptions { @@ -36,20 +40,28 @@ .HandleResult(r => r.StatusCode == HttpStatusCode.InternalServerError) .Handle(), // Register user callback called whenever retry occurs - OnRetry = outcome => { Console.WriteLine($"Retrying '{outcome.Result?.StatusCode}'..."); return default; }, - BaseDelay = TimeSpan.FromMilliseconds(400), - BackoffType = RetryBackoffType.Constant, - RetryCount = 3 + OnRetry = arguments => + { + Console.WriteLine($"Retrying '{arguments.Outcome.Result?.StatusCode}'..."); + return default; + }, + Delay = TimeSpan.FromMilliseconds(400), + BackoffType = DelayBackoffType.Constant, + MaxRetryAttempts = 3 }) .AddTimeout(new TimeoutStrategyOptions { Timeout = TimeSpan.FromSeconds(1), // Register user callback called whenever timeout occurs - OnTimeout = _ => { Console.WriteLine("Timeout occurred!"); return default; } + OnTimeout = _ => + { + Console.WriteLine("Timeout occurred!"); + return default; + } }) .Build(); -var response = await strategy.ExecuteAsync( +var response = await pipeline.ExecuteAsync( async token => { await Task.Delay(10, token); diff --git a/samples/Intro/Program.cs b/samples/Intro/Program.cs index 0fd022a282..889caa3cb7 100644 --- a/samples/Intro/Program.cs +++ b/samples/Intro/Program.cs @@ -3,46 +3,46 @@ using Polly.Timeout; // ------------------------------------------------------------------------ -// 1. Create a simple resilience strategy using CompositeStrategyBuilder +// 1. Create a simple resilience pipeline using ResiliencePipelineBuilder // ------------------------------------------------------------------------ -// The CompositeStrategyBuilder creates a ResilienceStrategy +// The ResiliencePipelineBuilder creates a ResiliencePipeline // that can be executed synchronously or asynchronously // and for both void and result-returning user-callbacks. -ResilienceStrategy strategy = new CompositeStrategyBuilder() +ResiliencePipeline pipeline = new ResiliencePipelineBuilder() // Use convenience extension that accepts TimeSpan .AddTimeout(TimeSpan.FromSeconds(5)) .Build(); // ------------------------------------------------------------------------ -// 2. Execute the strategy +// 2. Execute the pipeline // ------------------------------------------------------------------------ // Synchronously -strategy.Execute(() => { }); +pipeline.Execute(() => { }); // Asynchronously -await strategy.ExecuteAsync(async token => { await Task.Delay(10, token); }, CancellationToken.None); +await pipeline.ExecuteAsync(async token => await Task.Delay(10, token), CancellationToken.None); // Synchronously with result -strategy.Execute(token => "some-result"); +pipeline.Execute(token => "some-result"); // Asynchronously with result -await strategy.ExecuteAsync(async token => { await Task.Delay(10, token); return "some-result"; }, CancellationToken.None); +await pipeline.ExecuteAsync(async token => { await Task.Delay(10, token); return "some-result"; }, CancellationToken.None); // Use state to avoid lambda allocation -strategy.Execute(static state => state, "my-state"); +pipeline.Execute(static state => state, "my-state"); // ------------------------------------------------------------------------ // 3. Create and execute a pipeline of strategies // ------------------------------------------------------------------------ -strategy = new CompositeStrategyBuilder() +pipeline = new ResiliencePipelineBuilder() // Add retries using the options .AddRetry(new RetryStrategyOptions { // To configure the predicate you can use switch expressions - ShouldHandle = args => args.Exception switch + ShouldHandle = args => args.Outcome.Exception switch { TimeoutRejectedException => PredicateResult.True, @@ -51,10 +51,14 @@ _ => PredicateResult.False }, // Register user callback called whenever retry occurs - OnRetry = args => { Console.WriteLine($"Retrying...{args.Arguments.AttemptNumber} attempt"); return default; }, - BaseDelay = TimeSpan.FromMilliseconds(400), - BackoffType = RetryBackoffType.Constant, - RetryCount = 3 + OnRetry = args => + { + Console.WriteLine($"Retrying...{args.AttemptNumber} attempt"); + return default; + }, + Delay = TimeSpan.FromMilliseconds(400), + BackoffType = DelayBackoffType.Constant, + MaxRetryAttempts = 3 }) // Add timeout using the options .AddTimeout(new TimeoutStrategyOptions @@ -71,7 +75,7 @@ try { - await strategy.ExecuteAsync(async token => await Task.Delay(TimeSpan.FromSeconds(2), token), CancellationToken.None); + await pipeline.ExecuteAsync(async token => await Task.Delay(TimeSpan.FromSeconds(2), token), CancellationToken.None); } catch (TimeoutRejectedException) { diff --git a/samples/Retries/Program.cs b/samples/Retries/Program.cs index 46a922ad71..2585456b97 100644 --- a/samples/Retries/Program.cs +++ b/samples/Retries/Program.cs @@ -1,73 +1,73 @@ -using Polly; +using System.Net; +using Polly; using Polly.Retry; using Retries; -using System.Net; var helper = new ExecuteHelper(); // ------------------------------------------------------------------------ -// 1. Create a retry strategy that handles all exceptions +// 1. Create a retry pipeline that handles all exceptions // ------------------------------------------------------------------------ -ResilienceStrategy strategy = new CompositeStrategyBuilder() +ResiliencePipeline pipeline = new ResiliencePipelineBuilder() // Default retry options handle all exceptions .AddRetry(new RetryStrategyOptions()) .Build(); Console.WriteLine("---------------------------------------"); -strategy.Execute(helper.ExecuteUnstable); +pipeline.Execute(helper.ExecuteUnstable); // ------------------------------------------------------------------------ // 2. Customize the retry behavior // ------------------------------------------------------------------------ -strategy = new CompositeStrategyBuilder() +pipeline = new ResiliencePipelineBuilder() .AddRetry(new RetryStrategyOptions { // Specify what exceptions should be retried using PredicateBuilder ShouldHandle = new PredicateBuilder().Handle(), - RetryCount = 4, - BaseDelay = TimeSpan.FromSeconds(1), + MaxRetryAttempts = 4, + Delay = TimeSpan.FromSeconds(1), // The recommended backoff type for HTTP scenarios // See here for more information: https://github.com/App-vNext/Polly/wiki/Retry-with-jitter#more-complex-jitter - BackoffType = RetryBackoffType.Exponential, + BackoffType = DelayBackoffType.Exponential, UseJitter = true }) .Build(); Console.WriteLine("---------------------------------------"); -strategy.Execute(helper.ExecuteUnstable); +pipeline.Execute(helper.ExecuteUnstable); // ------------------------------------------------------------------------ // 3. Register the callbacks // ------------------------------------------------------------------------ -strategy = new CompositeStrategyBuilder() +pipeline = new ResiliencePipelineBuilder() .AddRetry(new RetryStrategyOptions { // Specify what exceptions should be retried using switch expressions - ShouldHandle = args => args.Exception switch + ShouldHandle = args => args.Outcome.Exception switch { InvalidOperationException => PredicateResult.True, _ => PredicateResult.False, }, OnRetry = outcome => { - Console.WriteLine($"Retrying attempt {outcome.Arguments.AttemptNumber}..."); + Console.WriteLine($"Retrying attempt {outcome.AttemptNumber}..."); return default; } }) .Build(); Console.WriteLine("---------------------------------------"); -strategy.Execute(helper.ExecuteUnstable); +pipeline.Execute(helper.ExecuteUnstable); // ------------------------------------------------------------------------ -// 4. Create an HTTP retry strategy that handles both exceptions and results +// 4. Create an HTTP retry pipeline that handles both exceptions and results // ------------------------------------------------------------------------ -ResilienceStrategy httpStrategy = new CompositeStrategyBuilder() +ResiliencePipeline httpPipeline = new ResiliencePipelineBuilder() .AddRetry(new RetryStrategyOptions { // Specify what exceptions or results should be retried @@ -76,19 +76,20 @@ .Handle() .HandleResult(r=>r.StatusCode == HttpStatusCode.InternalServerError), // Specify delay generator - RetryDelayGenerator = outcome => + DelayGenerator = arguments => { - if (outcome.Result is not null && outcome.Result.Headers.TryGetValues("Retry-After", out var value)) + if (arguments.Outcome.Result is not null && + arguments.Outcome.Result.Headers.TryGetValues("Retry-After", out var value)) { // Return delay based on header return new ValueTask(TimeSpan.FromSeconds(int.Parse(value.Single()))); } // Return delay hinted by the retry strategy - return new ValueTask(outcome.Arguments.DelayHint); + return new ValueTask(arguments.DelayHint); } }) .Build(); Console.WriteLine("---------------------------------------"); -httpStrategy.Execute(helper.ExecuteUnstable); +httpPipeline.Execute(helper.ExecuteUnstable);