From 9ff0986cd00092278e146eb5111f83739f422816 Mon Sep 17 00:00:00 2001 From: peter-csala <57183693+peter-csala@users.noreply.github.com> Date: Tue, 31 Oct 2023 17:09:01 +0100 Subject: [PATCH] [Docs] Add minor tweaks to migration guide 1/3 (#1763) * Revise Policies, Retry * Add tldr and links at end of each section * Add tldr and links at end of each section * Add missing static keywords * Review extra empty lines * Fix linting * Apply suggestions from code review --- docs/migration-v8.md | 194 +++++++++++++++--------- src/Snippets/Docs/Migration.Bulkhead.cs | 16 +- src/Snippets/Docs/Migration.Policies.cs | 76 +++++----- src/Snippets/Docs/Migration.Retry.cs | 36 ++--- 4 files changed, 193 insertions(+), 129 deletions(-) diff --git a/docs/migration-v8.md b/docs/migration-v8.md index 8b44e18e651..0a6179f6dc9 100644 --- a/docs/migration-v8.md +++ b/docs/migration-v8.md @@ -37,56 +37,57 @@ These interfaces were created and used as shown below: ```cs // Create and use the ISyncPolicy. -ISyncPolicy syncPolicy = Policy.Handle().WaitAndRetry(3, _ => TimeSpan.FromSeconds(1)); +ISyncPolicy syncPolicy = Policy + .Handle() + .WaitAndRetry(3, _ => TimeSpan.FromSeconds(1)); + syncPolicy.Execute(() => { - // Your code here + // Your code goes here }); // Create and use the IAsyncPolicy -IAsyncPolicy asyncPolicy = Policy.Handle().WaitAndRetryAsync(3, _ => TimeSpan.FromSeconds(1)); -await asyncPolicy.ExecuteAsync( - async cancellationToken => - { - // Your code here - }, - cancellationToken); +IAsyncPolicy asyncPolicy = Policy + .Handle() + .WaitAndRetryAsync(3, _ => TimeSpan.FromSeconds(1)); +await asyncPolicy.ExecuteAsync(async token => +{ + // Your code goes here +}, cancellationToken); // Create and use the ISyncPolicy -ISyncPolicy syncPolicyT = Policy - .HandleResult(r => !r.IsSuccessStatusCode) +ISyncPolicy syncPolicyT = Policy + .HandleResult(result => !result.IsSuccessStatusCode) .WaitAndRetry(3, _ => TimeSpan.FromSeconds(1)); syncPolicyT.Execute(() => { - // Your code here + // Your code goes here return GetResponse(); }); // Create and use the IAsyncPolicy -IAsyncPolicy asyncPolicyT = Policy - .HandleResult(r => !r.IsSuccessStatusCode) +IAsyncPolicy asyncPolicyT = Policy + .HandleResult(result => !result.IsSuccessStatusCode) .WaitAndRetryAsync(3, _ => TimeSpan.FromSeconds(1)); -await asyncPolicyT.ExecuteAsync( - async cancellationToken => - { - // Your code here - return await GetResponseAsync(cancellationToken); - }, - cancellationToken); + +await asyncPolicyT.ExecuteAsync(async token => +{ + // Your code goes here + return await GetResponseAsync(token); +}, cancellationToken); ``` ### Configuring strategies in v8 -In Polly v8, the previous code becomes: +In Polly v8, there are no such interfaces. The previous samples become: ```cs // Create and use the ResiliencePipeline. // -// The ResiliencePipelineBuilder is used to start building the resilience pipeline, -// instead of the static Policy.HandleException() call. +// Use the ResiliencePipelineBuilder to start building the resilience pipeline ResiliencePipeline pipeline = new ResiliencePipelineBuilder() .AddRetry(new RetryStrategyOptions { @@ -98,29 +99,27 @@ ResiliencePipeline pipeline = new ResiliencePipelineBuilder() .Build(); // After all necessary strategies are added, call Build() to create the pipeline. // Synchronous execution -pipeline.Execute(() => +pipeline.Execute(static () => { - // Your code here + // Your code goes here }); // Asynchronous execution is also supported with the same pipeline instance -await pipeline.ExecuteAsync(static async cancellationToken => +await pipeline.ExecuteAsync(static async token => { - // Your code here -}, -cancellationToken); + // Your code goes here +}, cancellationToken); // Create and use the ResiliencePipeline. // // Building of generic resilience pipeline is very similar to non-generic one. -// Notice the use of generic RetryStrategyOptions to configure the strategy -// as opposed to providing the arguments into the method. +// Notice the use of generic RetryStrategyOptions to configure the strategy. ResiliencePipeline pipelineT = new ResiliencePipelineBuilder() .AddRetry(new RetryStrategyOptions { ShouldHandle = new PredicateBuilder() .Handle() - .HandleResult(result => !result.IsSuccessStatusCode), + .HandleResult(static result => !result.IsSuccessStatusCode), Delay = TimeSpan.FromSeconds(1), MaxRetryAttempts = 3, BackoffType = DelayBackoffType.Constant @@ -128,27 +127,36 @@ ResiliencePipeline pipelineT = new ResiliencePipelineBuilde .Build(); // Synchronous execution -pipelineT.Execute(() => +pipelineT.Execute(static () => { - // Your code here + // Your code goes here return GetResponse(); }); // Asynchronous execution -await pipelineT.ExecuteAsync(static async cancellationToken => +await pipelineT.ExecuteAsync(static async token => { - // Your code here - return await GetResponseAsync(cancellationToken); -}, -cancellationToken); + // Your code goes here + return await GetResponseAsync(token); +}, cancellationToken); ``` +> [!IMPORTANT] +> +> Things to remember: +> +> - Use `ResiliencePipelineBuilder{}` to build a resiliency pipeline +> - Use one of the `Add*` builder methods to add a new strategy to the pipeline +> - Use either `Execute` or `ExecuteAsync` depending on the execution context +> +> For further information please check out the [Resilience pipelines documentation](pipelines/index.md). + ## Migrating policy wrap ### Policy wrap in v7 -Policy wrap is used to combine multiple policies into one as shown in the v7 example below: +Policy wrap is used to combine multiple policies into one: ```cs @@ -165,7 +173,7 @@ IAsyncPolicy wrappedPolicy = Policy.WrapAsync(retryPolicy, timeoutPolicy); ### Policy wrap in v8 -In v8, there's no need to use policy wrap explicitly. Instead, policy wrapping is integrated into `ResiliencePipelineBuilder`, as shown in the example below: +In v8, there's no need to use policy wrap explicitly. Instead, policy wrapping is integrated into `ResiliencePipelineBuilder`: ```cs @@ -185,12 +193,20 @@ ResiliencePipeline pipeline = new ResiliencePipelineBuilder() ``` -> [!NOTE] -> See [fallback after retries](strategies/fallback.md#fallback-after-retries) for an example on how the strategies are executed. +See [fallback after retries](strategies/fallback.md#fallback-after-retries) for an example on how the strategies are executed. + +> [!IMPORTANT] +> +> Things to remember: +> +> - Use `ResiliencePipelineBuilder{}` to build a resiliency pipeline +> - Use multiple `Add*` builder methods to add new strategies to your pipeline +> +> For further information please check out the [Resilience pipelines documentation](pipelines/index.md). ## Migrating retry policies -This section describes how to migrate the v7 retry policy to a resilience strategy in v8. +This section describes how to migrate v7 retry policies to V8 retry strategies. ### Retry in v7 @@ -200,13 +216,13 @@ In v7 the retry policy is configured as: ```cs // Retry once Policy - .Handle() - .Retry(); + .Handle() + .Retry(); // Retry multiple times Policy - .Handle() - .Retry(3); + .Handle() + .Retry(3); // Retry multiple times with callback Policy @@ -215,6 +231,11 @@ Policy { // Add logic to be executed before each retry, such as logging }); + +// Retry forever +Policy + .Handle() + .RetryForever(); ``` @@ -254,7 +275,7 @@ new ResiliencePipelineBuilder().AddRetry(new RetryStrategyOptions ShouldHandle = new PredicateBuilder().Handle(), MaxRetryAttempts = 3, Delay = TimeSpan.Zero, - OnRetry = args => + OnRetry = static args => { // Add logic to be executed before each retry, such as logging return default; @@ -278,15 +299,10 @@ new ResiliencePipelineBuilder().AddRetry(new RetryStrategyOptions ```cs -// Retry forever -Policy - .Handle() - .WaitAndRetryForever(_ => TimeSpan.FromSeconds(1)); - // Wait and retry multiple times Policy - .Handle() - .WaitAndRetry(3, _ => TimeSpan.FromSeconds(1)); + .Handle() + .WaitAndRetry(3, _ => TimeSpan.FromSeconds(1)); // Wait and retry multiple times with callback Policy @@ -324,7 +340,7 @@ new ResiliencePipelineBuilder().AddRetry(new RetryStrategyOptions MaxRetryAttempts = 3, Delay = TimeSpan.FromSeconds(1), BackoffType = DelayBackoffType.Constant, - OnRetry = args => + OnRetry = static args => { // Add logic to be executed before each retry, such as logging return default; @@ -350,9 +366,9 @@ new ResiliencePipelineBuilder().AddRetry(new RetryStrategyOptions ```cs // Wait and retry with result handling Policy - .Handle() - .OrResult(response => response.StatusCode == HttpStatusCode.InternalServerError) - .WaitAndRetry(3, _ => TimeSpan.FromSeconds(1)); + .Handle() + .OrResult(result => result.StatusCode == HttpStatusCode.InternalServerError) + .WaitAndRetry(3, _ => TimeSpan.FromSeconds(1)); ``` @@ -366,7 +382,7 @@ new ResiliencePipelineBuilder().AddRetry(new RetryStrategyO // PredicateBuilder is a convenience API that can used to configure the ShouldHandle predicate. ShouldHandle = new PredicateBuilder() .Handle() - .HandleResult(result => result.StatusCode == HttpStatusCode.InternalServerError), + .HandleResult(static result => result.StatusCode == HttpStatusCode.InternalServerError), MaxRetryAttempts = 3, }) .Build(); @@ -376,7 +392,7 @@ new ResiliencePipelineBuilder().AddRetry(new RetryStrategyO { // Determine what results to retry using switch expressions. // Note that PredicateResult.True() is just a shortcut for "new ValueTask(true)". - ShouldHandle = args => args.Outcome switch + ShouldHandle = static args => args.Outcome switch { { Exception: SomeExceptionType } => PredicateResult.True(), { Result: { StatusCode: HttpStatusCode.InternalServerError } } => PredicateResult.True(), @@ -388,7 +404,14 @@ new ResiliencePipelineBuilder().AddRetry(new RetryStrategyO ``` -It's important to remember that the configuration in v8 is options based, i.e. `RetryStrategyOptions` are used. +> [!IMPORTANT] +> +> Things to remember: +> +> - Use `AddRetry` to add a retry strategy to your resiliency pipeline +> - Use the `RetryStrategyOptions` to customize your retry behavior to meet your requirements +> +> For further information please check out the [Retry resilience strategy documentation](strategies/retry.md). ## Migrating rate limit policies @@ -452,6 +475,15 @@ ResiliencePipeline pipelineT = new ResiliencePipelineBuilde ``` +> [!IMPORTANT] +> +> Things to remember: +> +> - Use `AddRateLimiter` to add a rate limiter strategy to your resiliency pipeline +> - Use one of the derived classes of [`ReplenishingRateLimiter`](https://learn.microsoft.com/dotnet/api/system.threading.ratelimiting.replenishingratelimiter) to customize your rate limiter behavior to meet your requirements +> +> For further information please check out the [Rate limiter resilience strategy documentation](strategies/rate-limiter.md). + ## Migrating bulkhead policies The bulkhead policy is now replaced by the [rate limiter strategy](strategies/rate-limiter.md) which uses the [`System.Threading.RateLimiting`](https://www.nuget.org/packages/System.Threading.RateLimiting) package. The new counterpart to bulkhead is `ConcurrencyLimiter`. @@ -464,16 +496,24 @@ The bulkhead policy is now replaced by the [rate limiter strategy](strategies/ra ```cs // Create sync bulkhead -ISyncPolicy syncPolicy = Policy.Bulkhead(maxParallelization: 100, maxQueuingActions: 50); +ISyncPolicy syncPolicy = Policy.Bulkhead( + maxParallelization: 100, + maxQueuingActions: 50); // Create async bulkhead -IAsyncPolicy asyncPolicy = Policy.BulkheadAsync(maxParallelization: 100, maxQueuingActions: 50); +IAsyncPolicy asyncPolicy = Policy.BulkheadAsync( + maxParallelization: 100, + maxQueuingActions: 50); // Create generic sync bulkhead -ISyncPolicy syncPolicyT = Policy.Bulkhead(maxParallelization: 100, maxQueuingActions: 50); +ISyncPolicy syncPolicyT = Policy.Bulkhead( + maxParallelization: 100, + maxQueuingActions: 50); // Create generic async bulkhead -IAsyncPolicy asyncPolicyT = Policy.BulkheadAsync(maxParallelization: 100, maxQueuingActions: 50); +IAsyncPolicy asyncPolicyT = Policy.BulkheadAsync( + maxParallelization: 100, + maxQueuingActions: 50); ``` @@ -498,6 +538,15 @@ ResiliencePipeline pipelineT = new ResiliencePipelineBuilde ``` +> [!IMPORTANT] +> +> Things to remember: +> +> - Use `AddConcurrencyLimiter` to add a concurrency limiter strategy to your resiliency pipeline +> - Use the `ConcurrencyLimiterOptions` to customize your concurrency limiter behavior to meet your requirements +> +> For further information please check out the [Rate limiter resilience strategy documentation](strategies/rate-limiter.md). + ## Migrating timeout policies > [!NOTE] @@ -539,6 +588,15 @@ ResiliencePipeline pipelineT = new ResiliencePipelineBuilde ``` +> [!IMPORTANT] +> +> Things to remember: +> +> - Use `AddTimeout` to add a timeout strategy to your resiliency pipeline +> - Use the `TimeoutStrategyOptions` to customize your timeout behavior to meet your requirements +> +> For further information please check out the [Timeout resilience strategy documentation](strategies/timeout.md). + ## Migrating other policies Migrating is a process similar to the ones described in the previous sections. Keep in mind that: diff --git a/src/Snippets/Docs/Migration.Bulkhead.cs b/src/Snippets/Docs/Migration.Bulkhead.cs index a445b7a39d6..5439539def1 100644 --- a/src/Snippets/Docs/Migration.Bulkhead.cs +++ b/src/Snippets/Docs/Migration.Bulkhead.cs @@ -9,16 +9,24 @@ public static void Bulkhead_V7() #region migration-bulkhead-v7 // Create sync bulkhead - ISyncPolicy syncPolicy = Policy.Bulkhead(maxParallelization: 100, maxQueuingActions: 50); + ISyncPolicy syncPolicy = Policy.Bulkhead( + maxParallelization: 100, + maxQueuingActions: 50); // Create async bulkhead - IAsyncPolicy asyncPolicy = Policy.BulkheadAsync(maxParallelization: 100, maxQueuingActions: 50); + IAsyncPolicy asyncPolicy = Policy.BulkheadAsync( + maxParallelization: 100, + maxQueuingActions: 50); // Create generic sync bulkhead - ISyncPolicy syncPolicyT = Policy.Bulkhead(maxParallelization: 100, maxQueuingActions: 50); + ISyncPolicy syncPolicyT = Policy.Bulkhead( + maxParallelization: 100, + maxQueuingActions: 50); // Create generic async bulkhead - IAsyncPolicy asyncPolicyT = Policy.BulkheadAsync(maxParallelization: 100, maxQueuingActions: 50); + IAsyncPolicy asyncPolicyT = Policy.BulkheadAsync( + maxParallelization: 100, + maxQueuingActions: 50); #endregion } diff --git a/src/Snippets/Docs/Migration.Policies.cs b/src/Snippets/Docs/Migration.Policies.cs index 77c1ecaef40..2c13bd9f50d 100644 --- a/src/Snippets/Docs/Migration.Policies.cs +++ b/src/Snippets/Docs/Migration.Policies.cs @@ -12,43 +12,45 @@ public static async Task Policies() #region migration-policies-v7 // Create and use the ISyncPolicy. - ISyncPolicy syncPolicy = Policy.Handle().WaitAndRetry(3, _ => TimeSpan.FromSeconds(1)); + ISyncPolicy syncPolicy = Policy + .Handle() + .WaitAndRetry(3, _ => TimeSpan.FromSeconds(1)); + syncPolicy.Execute(() => { - // Your code here + // Your code goes here }); // Create and use the IAsyncPolicy - IAsyncPolicy asyncPolicy = Policy.Handle().WaitAndRetryAsync(3, _ => TimeSpan.FromSeconds(1)); - await asyncPolicy.ExecuteAsync( - async cancellationToken => - { - // Your code here - }, - cancellationToken); + IAsyncPolicy asyncPolicy = Policy + .Handle() + .WaitAndRetryAsync(3, _ => TimeSpan.FromSeconds(1)); + await asyncPolicy.ExecuteAsync(async token => + { + // Your code goes here + }, cancellationToken); // Create and use the ISyncPolicy - ISyncPolicy syncPolicyT = Policy - .HandleResult(r => !r.IsSuccessStatusCode) + ISyncPolicy syncPolicyT = Policy + .HandleResult(result => !result.IsSuccessStatusCode) .WaitAndRetry(3, _ => TimeSpan.FromSeconds(1)); syncPolicyT.Execute(() => { - // Your code here + // Your code goes here return GetResponse(); }); // Create and use the IAsyncPolicy - IAsyncPolicy asyncPolicyT = Policy - .HandleResult(r => !r.IsSuccessStatusCode) + IAsyncPolicy asyncPolicyT = Policy + .HandleResult(result => !result.IsSuccessStatusCode) .WaitAndRetryAsync(3, _ => TimeSpan.FromSeconds(1)); - await asyncPolicyT.ExecuteAsync( - async cancellationToken => - { - // Your code here - return await GetResponseAsync(cancellationToken); - }, - cancellationToken); + + await asyncPolicyT.ExecuteAsync(async token => + { + // Your code goes here + return await GetResponseAsync(token); + }, cancellationToken); #endregion } @@ -61,8 +63,7 @@ public static async Task Strategies() // Create and use the ResiliencePipeline. // - // The ResiliencePipelineBuilder is used to start building the resilience pipeline, - // instead of the static Policy.HandleException() call. + // Use the ResiliencePipelineBuilder to start building the resilience pipeline ResiliencePipeline pipeline = new ResiliencePipelineBuilder() .AddRetry(new RetryStrategyOptions { @@ -74,29 +75,27 @@ public static async Task Strategies() .Build(); // After all necessary strategies are added, call Build() to create the pipeline. // Synchronous execution - pipeline.Execute(() => + pipeline.Execute(static () => { - // Your code here + // Your code goes here }); // Asynchronous execution is also supported with the same pipeline instance - await pipeline.ExecuteAsync(static async cancellationToken => + await pipeline.ExecuteAsync(static async token => { - // Your code here - }, - cancellationToken); + // Your code goes here + }, cancellationToken); // Create and use the ResiliencePipeline. // // Building of generic resilience pipeline is very similar to non-generic one. - // Notice the use of generic RetryStrategyOptions to configure the strategy - // as opposed to providing the arguments into the method. + // Notice the use of generic RetryStrategyOptions to configure the strategy. ResiliencePipeline pipelineT = new ResiliencePipelineBuilder() .AddRetry(new RetryStrategyOptions { ShouldHandle = new PredicateBuilder() .Handle() - .HandleResult(result => !result.IsSuccessStatusCode), + .HandleResult(static result => !result.IsSuccessStatusCode), Delay = TimeSpan.FromSeconds(1), MaxRetryAttempts = 3, BackoffType = DelayBackoffType.Constant @@ -104,19 +103,18 @@ await pipeline.ExecuteAsync(static async cancellationToken => .Build(); // Synchronous execution - pipelineT.Execute(() => + pipelineT.Execute(static () => { - // Your code here + // Your code goes here return GetResponse(); }); // Asynchronous execution - await pipelineT.ExecuteAsync(static async cancellationToken => + await pipelineT.ExecuteAsync(static async token => { - // Your code here - return await GetResponseAsync(cancellationToken); - }, - cancellationToken); + // Your code goes here + return await GetResponseAsync(token); + }, cancellationToken); #endregion } diff --git a/src/Snippets/Docs/Migration.Retry.cs b/src/Snippets/Docs/Migration.Retry.cs index 8947f95a073..de97e046166 100644 --- a/src/Snippets/Docs/Migration.Retry.cs +++ b/src/Snippets/Docs/Migration.Retry.cs @@ -15,13 +15,13 @@ public static void Retry_V7() // Retry once Policy - .Handle() - .Retry(); + .Handle() + .Retry(); // Retry multiple times Policy - .Handle() - .Retry(3); + .Handle() + .Retry(3); // Retry multiple times with callback Policy @@ -31,19 +31,19 @@ public static void Retry_V7() // Add logic to be executed before each retry, such as logging }); - #endregion - - #region migration-retry-wait-v7 - // Retry forever Policy .Handle() - .WaitAndRetryForever(_ => TimeSpan.FromSeconds(1)); + .RetryForever(); + + #endregion + + #region migration-retry-wait-v7 // Wait and retry multiple times Policy - .Handle() - .WaitAndRetry(3, _ => TimeSpan.FromSeconds(1)); + .Handle() + .WaitAndRetry(3, _ => TimeSpan.FromSeconds(1)); // Wait and retry multiple times with callback Policy @@ -64,9 +64,9 @@ public static void Retry_V7() // Wait and retry with result handling Policy - .Handle() - .OrResult(response => response.StatusCode == HttpStatusCode.InternalServerError) - .WaitAndRetry(3, _ => TimeSpan.FromSeconds(1)); + .Handle() + .OrResult(result => result.StatusCode == HttpStatusCode.InternalServerError) + .WaitAndRetry(3, _ => TimeSpan.FromSeconds(1)); #endregion } @@ -105,7 +105,7 @@ public static void Retry_V8() ShouldHandle = new PredicateBuilder().Handle(), MaxRetryAttempts = 3, Delay = TimeSpan.Zero, - OnRetry = args => + OnRetry = static args => { // Add logic to be executed before each retry, such as logging return default; @@ -144,7 +144,7 @@ public static void Retry_V8() MaxRetryAttempts = 3, Delay = TimeSpan.FromSeconds(1), BackoffType = DelayBackoffType.Constant, - OnRetry = args => + OnRetry = static args => { // Add logic to be executed before each retry, such as logging return default; @@ -172,7 +172,7 @@ public static void Retry_V8() // PredicateBuilder is a convenience API that can used to configure the ShouldHandle predicate. ShouldHandle = new PredicateBuilder() .Handle() - .HandleResult(result => result.StatusCode == HttpStatusCode.InternalServerError), + .HandleResult(static result => result.StatusCode == HttpStatusCode.InternalServerError), MaxRetryAttempts = 3, }) .Build(); @@ -182,7 +182,7 @@ public static void Retry_V8() { // Determine what results to retry using switch expressions. // Note that PredicateResult.True() is just a shortcut for "new ValueTask(true)". - ShouldHandle = args => args.Outcome switch + ShouldHandle = static args => args.Outcome switch { { Exception: SomeExceptionType } => PredicateResult.True(), { Result: { StatusCode: HttpStatusCode.InternalServerError } } => PredicateResult.True(),