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

[Docs] Minor cleanups #1768

Merged
merged 7 commits into from
Nov 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions docs/migration-v8.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ await pipelineT.ExecuteAsync(static async token =>
```
<!-- endSnippet -->

> [!IMPORTANT]
> [!TIP]
>
> Things to remember:
>
Expand Down Expand Up @@ -195,7 +195,7 @@ ResiliencePipeline pipeline = new ResiliencePipelineBuilder()

See [fallback after retries](strategies/fallback.md#fallback-after-retries) for an example on how the strategies are executed.

> [!IMPORTANT]
> [!TIP]
>
> Things to remember:
>
Expand Down Expand Up @@ -404,7 +404,7 @@ new ResiliencePipelineBuilder<HttpResponseMessage>().AddRetry(new RetryStrategyO
```
<!-- endSnippet -->

> [!IMPORTANT]
> [!TIP]
>
> Things to remember:
>
Expand Down Expand Up @@ -475,7 +475,7 @@ ResiliencePipeline<HttpResponseMessage> pipelineT = new ResiliencePipelineBuilde
```
<!-- endSnippet -->

> [!IMPORTANT]
> [!TIP]
>
> Things to remember:
>
Expand Down Expand Up @@ -538,7 +538,7 @@ ResiliencePipeline<HttpResponseMessage> pipelineT = new ResiliencePipelineBuilde
```
<!-- endSnippet -->

> [!IMPORTANT]
> [!TIP]
>
> Things to remember:
>
Expand Down Expand Up @@ -588,7 +588,7 @@ ResiliencePipeline<HttpResponseMessage> pipelineT = new ResiliencePipelineBuilde
```
<!-- endSnippet -->

> [!IMPORTANT]
> [!TIP]
>
> Things to remember:
>
Expand Down Expand Up @@ -689,7 +689,7 @@ cbPolicy.Reset(); // Transitions into the Closed state

### Circuit breaker in v8

> [!IMPORTANT]
> [!TIP]
>
> Polly V8 does not support the standard (*"classic"*) circuit breaker with consecutive failure counting.
>
Expand Down Expand Up @@ -756,11 +756,11 @@ await manualControl.CloseAsync(); // Transitions into the Closed state
>
> You could guard the `Execute{Async}` call with a condition that the circuit is not broken. This technique does **not** work with V8.
>
> Under the [circuit breaker's anti-patterns](strategies/circuit-breaker.md#4---reducing-thrown-exceptions) you can find the suggested way for V8.
> Under the [circuit breaker's anti-patterns](strategies/circuit-breaker.md#reducing-thrown-exceptions) you can find the suggested way for V8.

____

> [!IMPORTANT]
> [!TIP]
>
> Things to remember:
>
Expand Down
22 changes: 11 additions & 11 deletions docs/strategies/circuit-breaker.md
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ sequenceDiagram

Over the years, many developers have used Polly in various ways. Some of these recurring patterns may not be ideal. This section highlights the recommended practices and those to avoid.

### 1 - Using different sleep duration between retry attempts based on Circuit Breaker state
### Using different sleep duration between retry attempts based on Circuit Breaker state

Imagine that we have an inner Circuit Breaker and an outer Retry strategies.

Expand All @@ -318,7 +318,7 @@ We would like to define the retry in a way that the sleep duration calculation i

Use a closure to branch based on circuit breaker state:

<!-- snippet: circuit-breaker-anti-pattern-1 -->
<!-- snippet: circuit-breaker-anti-pattern-circuit-aware-retry -->
```cs
var stateProvider = new CircuitBreakerStateProvider();
var circuitBreaker = new ResiliencePipelineBuilder()
Expand Down Expand Up @@ -362,7 +362,7 @@ var retry = new ResiliencePipelineBuilder()

Use `Context` to pass information between strategies:

<!-- snippet: circuit-breaker-pattern-1 -->
<!-- snippet: circuit-breaker-pattern-circuit-aware-retry -->
```cs
var circuitBreaker = new ResiliencePipelineBuilder()
.AddCircuitBreaker(new()
Expand Down Expand Up @@ -406,7 +406,7 @@ var retry = new ResiliencePipelineBuilder()
- The Retry strategy fetches the sleep duration dynamically without knowing any specific knowledge about the Circuit Breaker.
- If adjustments are needed for the `BreakDuration`, they can be made in one place.

### 2 - Using different duration for breaks
### Using different duration for breaks

In the case of Retry you can specify dynamically the sleep duration via the `DelayGenerator`.

Expand All @@ -416,7 +416,7 @@ In the case of Circuit Breaker the `BreakDuration` is considered constant (can't

Use `Task.Delay` inside `OnOpened`:

<!-- snippet: circuit-breaker-anti-pattern-2 -->
<!-- snippet: circuit-breaker-anti-pattern-sleep-duration-generator -->
```cs
static IEnumerable<TimeSpan> GetSleepDuration()
{
Expand Down Expand Up @@ -450,7 +450,7 @@ var circuitBreaker = new ResiliencePipelineBuilder()
- The minimum break duration value is half a second. This implies that each sleep lasts for `sleepDurationProvider.Current` plus an additional half a second.
- One might think that setting the `BreakDuration` to `sleepDurationProvider.Current` would address this, but it doesn't. This is because the `BreakDuration` is established only once and isn't re-assessed during each break.

<!-- snippet: circuit-breaker-anti-pattern-2-ext -->
<!-- snippet: circuit-breaker-anti-pattern-sleep-duration-generator-ext -->
```cs
circuitBreaker = new ResiliencePipelineBuilder()
.AddCircuitBreaker(new()
Expand All @@ -472,7 +472,7 @@ circuitBreaker = new ResiliencePipelineBuilder()

The `CircuitBreakerStrategyOptions` currently do not support defining break durations dynamically. This may be re-evaluated in the future. For now, refer to the first example for a potential workaround. However, please use it with caution.

### 3 - Wrapping each endpoint with a circuit breaker
### Wrapping each endpoint with a circuit breaker

Imagine that you have to call N number of services via `HttpClient`s.
You want to decorate all downstream calls with the service-aware Circuit Breaker.
Expand All @@ -481,7 +481,7 @@ You want to decorate all downstream calls with the service-aware Circuit Breaker

Use a collection of Circuit Breakers and explicitly call `ExecuteAsync()`:

<!-- snippet: circuit-breaker-anti-pattern-3 -->
<!-- snippet: circuit-breaker-anti-pattern-cb-per-endpoint -->
```cs
// Defined in a common place
var uriToCbMappings = new Dictionary<Uri, ResiliencePipeline>
Expand Down Expand Up @@ -536,7 +536,7 @@ public Downstream1Client(
> It is required because the `AddPolicyHandler()` method anticipates an `IAsyncPolicy<HttpResponse>` parameter.
> Please be aware that, later an `AddResilienceHandler()` will be introduced in the `Microsoft.Extensions.Http.Resilience` package which is the successor of the `Microsoft.Extensions.Http.Polly`.

### 4 - Reducing thrown exceptions
### Reducing thrown exceptions

In case of Circuit Breaker when it is either in the `Open` or `Isolated` state new requests are rejected immediately.

Expand All @@ -546,7 +546,7 @@ That means the strategy will throw either a `BrokenCircuitException` or an `Isol

Use guard expression to call `Execute{Async}` only if the circuit is not broken:

<!-- snippet: circuit-breaker-anti-pattern-4 -->
<!-- snippet: circuit-breaker-anti-pattern-reduce-thrown-exceptions -->
```cs
var stateProvider = new CircuitBreakerStateProvider();
var circuitBreaker = new ResiliencePipelineBuilder()
Expand Down Expand Up @@ -582,7 +582,7 @@ if (stateProvider.CircuitState

Use `ExecuteOutcomeAsync` to avoid throwing exception:

<!-- snippet: circuit-breaker-pattern-4 -->
<!-- snippet: circuit-breaker-pattern-reduce-thrown-exceptions -->
```cs
var context = ResilienceContextPool.Shared.Get();
var circuitBreaker = new ResiliencePipelineBuilder()
Expand Down
22 changes: 11 additions & 11 deletions docs/strategies/fallback.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ sequenceDiagram

When designing resilient systems, a common pattern is to use a fallback after multiple failed retry attempts. This approach is especially relevant when a fallback strategy can provide a sensible default value.

<!-- snippet: fallback-after-retries -->
<!-- snippet: fallback-pattern-after-retries -->
```cs
// Define a common predicates re-used by both fallback and retries
var predicateBuilder = new PredicateBuilder<HttpResponseMessage>()
Expand Down Expand Up @@ -156,13 +156,13 @@ Here's a breakdown of the behavior when the callback produces either an `HttpSta

Over the years, many developers have used Polly in various ways. Some of these recurring patterns may not be ideal. This section highlights the recommended practices and ones to avoid.

### 1 - Using fallback to replace thrown exception
### Using fallback to replace thrown exception

❌ DON'T

Throw custom exceptions from the `OnFallback` delegate:

<!-- snippet: fallback-anti-pattern-1 -->
<!-- snippet: fallback-anti-pattern-replace-exception -->
```cs
var fallback = new ResiliencePipelineBuilder<HttpResponseMessage>()
.AddFallback(new()
Expand All @@ -183,7 +183,7 @@ Throwing an exception from a user-defined delegate can disrupt the normal contro

Use `ExecuteOutcomeAsync` and then evaluate the `Exception`:

<!-- snippet: fallback-pattern-1 -->
<!-- snippet: fallback-pattern-replace-exception -->
```cs
var outcome = await WhateverPipeline.ExecuteOutcomeAsync(Action, context, "state");
if (outcome.Exception is HttpRequestException requestException)
Expand All @@ -197,7 +197,7 @@ if (outcome.Exception is HttpRequestException requestException)

This method lets you execute the strategy or pipeline smoothly, without unexpected interruptions. If you repeatedly find yourself writing this exception "remapping" logic, consider marking the method you wish to decorate as `private` and expose the "remapping" logic publicly.

<!-- snippet: fallback-pattern-1-ext -->
<!-- snippet: fallback-pattern-replace-exception-ext -->
```cs
public static async ValueTask<HttpResponseMessage> Action()
{
Expand Down Expand Up @@ -226,15 +226,15 @@ private static ValueTask<HttpResponseMessage> ActionCore()
```
<!-- endSnippet -->

### 2 - Using retry for fallback
### Using retry for fallback

Suppose you have a primary and a secondary endpoint. If the primary fails, you want to call the secondary.

❌ DON'T

Use retry for fallback:

<!-- snippet: fallback-anti-pattern-2 -->
<!-- snippet: fallback-anti-pattern-retry-for-fallback -->
```cs
var fallback = new ResiliencePipelineBuilder<HttpResponseMessage>()
.AddRetry(new()
Expand Down Expand Up @@ -275,7 +275,7 @@ A retry strategy by default executes the same operation up to `N` times, where `

Use fallback to call the secondary:

<!-- snippet: fallback-pattern-2 -->
<!-- snippet: fallback-pattern-retry-for-fallback -->
```cs
var fallback = new ResiliencePipelineBuilder<HttpResponseMessage>()
.AddFallback(new()
Expand All @@ -295,7 +295,7 @@ return await fallback.ExecuteAsync(CallPrimary, CancellationToken.None);
- The target code is executed only once.
- The fallback value is returned directly, eliminating the need for additional code like `Context` or `ExecuteOutcomeAsync()`.

### 3 - Nesting `ExecuteAsync` calls
### Nesting `ExecuteAsync` calls

Combining multiple strategies can be achieved in various ways. However, deeply nesting `ExecuteAsync` calls can lead to what's commonly referred to as _`Execute` Hell_.

Expand All @@ -306,7 +306,7 @@ Combining multiple strategies can be achieved in various ways. However, deeply n

Nest `ExecuteAsync` calls:

<!-- snippet: fallback-anti-pattern-3 -->
<!-- snippet: fallback-anti-pattern-nesting-execute -->
```cs
var result = await fallback.ExecuteAsync(async (CancellationToken outerCT) =>
{
Expand All @@ -328,7 +328,7 @@ This is akin to JavaScript's [callback hell](http://callbackhell.com/) or _[the

Use `ResiliencePipelineBuilder` to chain strategies:

<!-- snippet: fallback-pattern-3 -->
<!-- snippet: fallback-pattern-nesting-execute -->
```cs
var pipeline = new ResiliencePipelineBuilder<HttpResponseMessage>()
.AddPipeline(timeout)
Expand Down
Loading