Skip to content

Commit c5d268d

Browse files
authored
[Docs] Improve timeout docs (#1767)
1 parent 84236fb commit c5d268d

File tree

3 files changed

+84
-1
lines changed

3 files changed

+84
-1
lines changed

docs/strategies/timeout.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@
1010

1111
---
1212

13+
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`.
14+
15+
> ![IMPORTANT]
16+
> 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.
17+
1318
## Usage
1419

1520
<!-- snippet: timeout -->
@@ -119,3 +124,47 @@ sequenceDiagram
119124
T->>P: Throws <br/>TimeoutRejectedException
120125
P->>C: Propagates exception
121126
```
127+
128+
## Anti-patterns
129+
130+
### Ignoring Cancellation Token
131+
132+
❌ DON'T
133+
134+
Ignore the cancellation token provided by the resilience pipeline:
135+
136+
<!-- snippet: timeout-ignore-cancellation-token -->
137+
```cs
138+
var pipeline = new ResiliencePipelineBuilder()
139+
.AddTimeout(TimeSpan.FromSeconds(1))
140+
.Build();
141+
142+
await pipeline.ExecuteAsync(
143+
async innerToken => await Task.Delay(TimeSpan.FromSeconds(3), outerToken), // The delay call should use innerToken
144+
outerToken);
145+
```
146+
<!-- endSnippet -->
147+
148+
**Reasoning**:
149+
150+
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.
151+
152+
✅ DO
153+
154+
Respect the cancellation token provided by the pipeline:
155+
156+
<!-- snippet: timeout-respect-cancellation-token -->
157+
```cs
158+
var pipeline = new ResiliencePipelineBuilder()
159+
.AddTimeout(TimeSpan.FromSeconds(1))
160+
.Build();
161+
162+
await pipeline.ExecuteAsync(
163+
static async innerToken => await Task.Delay(TimeSpan.FromSeconds(3), innerToken),
164+
outerToken);
165+
```
166+
<!-- endSnippet -->
167+
168+
**Reasoning**:
169+
170+
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.

src/Polly.Core/Retry/RetryStrategyOptions.TResult.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ public class RetryStrategyOptions<TResult> : ResilienceStrategyOptions
6767
/// <see cref="DelayBackoffType.Constant"/> Represents the constant delay between retries.
6868
/// </item>
6969
/// </list>
70-
/// This property is ignored when <see cref="DelayGenerator"/> is set.
70+
/// This property is ignored when <see cref="DelayGenerator"/> is set and returns a valid <see cref="TimeSpan"/> value.
7171
/// </remarks>
7272
/// <value>
7373
/// The default value is 2 seconds.

src/Snippets/Docs/Timeout.cs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,4 +66,38 @@ public static async Task Usage()
6666

6767
#endregion
6868
}
69+
70+
public static async Task IgnoreCancellationToken()
71+
{
72+
var outerToken = CancellationToken.None;
73+
74+
#region timeout-ignore-cancellation-token
75+
76+
var pipeline = new ResiliencePipelineBuilder()
77+
.AddTimeout(TimeSpan.FromSeconds(1))
78+
.Build();
79+
80+
await pipeline.ExecuteAsync(
81+
async innerToken => await Task.Delay(TimeSpan.FromSeconds(3), outerToken), // The delay call should use innerToken
82+
outerToken);
83+
84+
#endregion
85+
}
86+
87+
public static async Task RespectCancellationToken()
88+
{
89+
var outerToken = CancellationToken.None;
90+
91+
#region timeout-respect-cancellation-token
92+
93+
var pipeline = new ResiliencePipelineBuilder()
94+
.AddTimeout(TimeSpan.FromSeconds(1))
95+
.Build();
96+
97+
await pipeline.ExecuteAsync(
98+
static async innerToken => await Task.Delay(TimeSpan.FromSeconds(3), innerToken),
99+
outerToken);
100+
101+
#endregion
102+
}
69103
}

0 commit comments

Comments
 (0)