Skip to content

Commit

Permalink
[Docs] Improve timeout docs (#1767)
Browse files Browse the repository at this point in the history
  • Loading branch information
martintmk authored Nov 2, 2023
1 parent 84236fb commit c5d268d
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 1 deletion.
49 changes: 49 additions & 0 deletions docs/strategies/timeout.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@

---

The timeout resilience strategy cancels the execution if it does not complete within the specified timeout period. If the execution is canceled by the timeout strategy, it throws a `TimeoutRejectedException`. The timeout strategy operates by wrapping the incoming cancellation token with a new one. Should the original token be canceled, the timeout strategy will transparently honor the original cancellation token without throwing a `TimeoutRejectedException`.

> ![IMPORTANT]
> It is crucial that the user's callback respects the cancellation token. If it does not, the callback will continue executing even after a cancellation request, thereby ignoring the cancellation.
## Usage

<!-- snippet: timeout -->
Expand Down Expand Up @@ -119,3 +124,47 @@ sequenceDiagram
T->>P: Throws <br/>TimeoutRejectedException
P->>C: Propagates exception
```

## Anti-patterns

### Ignoring Cancellation Token

❌ DON'T

Ignore the cancellation token provided by the resilience pipeline:

<!-- snippet: timeout-ignore-cancellation-token -->
```cs
var pipeline = new ResiliencePipelineBuilder()
.AddTimeout(TimeSpan.FromSeconds(1))
.Build();

await pipeline.ExecuteAsync(
async innerToken => await Task.Delay(TimeSpan.FromSeconds(3), outerToken), // The delay call should use innerToken
outerToken);
```
<!-- endSnippet -->

**Reasoning**:

The provided callback ignores the `innerToken` passed from the pipeline and instead uses the `outerToken`. For this reason, the cancelled `innerToken` is ignored, and the callback is not cancelled within 1 second.

✅ DO

Respect the cancellation token provided by the pipeline:

<!-- snippet: timeout-respect-cancellation-token -->
```cs
var pipeline = new ResiliencePipelineBuilder()
.AddTimeout(TimeSpan.FromSeconds(1))
.Build();

await pipeline.ExecuteAsync(
static async innerToken => await Task.Delay(TimeSpan.FromSeconds(3), innerToken),
outerToken);
```
<!-- endSnippet -->

**Reasoning**:

The provided callback respects the `innerToken` provided by the pipeline, and as a result, the callback is correctly cancelled by the timeout strategy after 1 second plus `TimeoutRejectedException` is thrown.
2 changes: 1 addition & 1 deletion src/Polly.Core/Retry/RetryStrategyOptions.TResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public class RetryStrategyOptions<TResult> : ResilienceStrategyOptions
/// <see cref="DelayBackoffType.Constant"/> Represents the constant delay between retries.
/// </item>
/// </list>
/// This property is ignored when <see cref="DelayGenerator"/> is set.
/// This property is ignored when <see cref="DelayGenerator"/> is set and returns a valid <see cref="TimeSpan"/> value.
/// </remarks>
/// <value>
/// The default value is 2 seconds.
Expand Down
34 changes: 34 additions & 0 deletions src/Snippets/Docs/Timeout.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,38 @@ public static async Task Usage()

#endregion
}

public static async Task IgnoreCancellationToken()
{
var outerToken = CancellationToken.None;

#region timeout-ignore-cancellation-token

var pipeline = new ResiliencePipelineBuilder()
.AddTimeout(TimeSpan.FromSeconds(1))
.Build();

await pipeline.ExecuteAsync(
async innerToken => await Task.Delay(TimeSpan.FromSeconds(3), outerToken), // The delay call should use innerToken
outerToken);

#endregion
}

public static async Task RespectCancellationToken()
{
var outerToken = CancellationToken.None;

#region timeout-respect-cancellation-token

var pipeline = new ResiliencePipelineBuilder()
.AddTimeout(TimeSpan.FromSeconds(1))
.Build();

await pipeline.ExecuteAsync(
static async innerToken => await Task.Delay(TimeSpan.FromSeconds(3), innerToken),
outerToken);

#endregion
}
}

0 comments on commit c5d268d

Please sign in to comment.