Skip to content

Commit 1dcfc01

Browse files
authoredJan 25, 2024
[Docs] Add delay calculation diagrams (#1922)
Replace textual descriptions with diagrams.
1 parent 51044c5 commit 1dcfc01

File tree

1 file changed

+129
-59
lines changed

1 file changed

+129
-59
lines changed
 

Diff for: ‎docs/strategies/retry.md

+129-59
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ new ResiliencePipelineBuilder<HttpResponseMessage>().AddRetry(optionsExtractDela
9898
## Defaults
9999

100100
| Property | Default Value | Description |
101-
| ------------------ | -------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
101+
|--------------------|----------------------------------------------------------------------------|------------------------------------------------------------------------------------------|
102102
| `ShouldHandle` | Predicate that handles all exceptions except `OperationCanceledException`. | Predicate that determines what results and exceptions are handled by the retry strategy. |
103103
| `MaxRetryAttempts` | 3 | The maximum number of retries to use, in addition to the original call. |
104104
| `Delay` | 2 seconds | The base delay between retries. |
@@ -116,9 +116,10 @@ There are many properties that may contribute to this calculation:
116116

117117
- `BackoffType`: Specifies which calculation algorithm should run.
118118
- `Delay`: If only this property is specified then it will be used as-is. If others are also specified then this will be used as a *base delay*.
119-
- `DelayGenerator`: If specified, will override other property-based calculations, **except** if it returns `null` or a negative `TimeSpan`, in which case the other property-based calculations are used.
119+
- `DelayGenerator`: If specified, overrides other property-based calculations, **except** if it returns `null` or a negative `TimeSpan`, in which case the other property-based calculations are used.
120120
- `MaxDelay`: If specified, caps the delay if the calculated delay is greater than this value, **except** if `DelayGenerator` is used, where no capping is applied.
121-
- `UseJitter`: If enabled, then adds a random value between between -25% of `Delay` and +25% of `Delay`, **except** if `BackoffType` is `Exponential`, where a bit more complex jitter calculation is used.
121+
- `UseJitter`: If enabled, adds a random value between -25% and +25% of the calculated `Delay`, **except** if `BackoffType` is `Exponential`, where a `DecorrelatedJitterBackoffV2` formula is used for jitter calculation.
122+
- That formula is based on [Polly.Contrib.WaitAndRetry](https://github.com/Polly-Contrib/Polly.Contrib.WaitAndRetry).
122123

123124
> [!IMPORTANT]
124125
> The summarized description below is an implementation detail. It may change in the future without notice.
@@ -127,84 +128,153 @@ The `BackoffType` property's data type is the [`DelayBackoffType`](xref:Polly.De
127128

128129
### Constant
129130

130-
Even though the `Constant` name could imply that only the `Delay` property is used, in reality all the above listed properties are used.
131-
132-
Step 1: Calculating the base delay:
133-
134-
- If `UseJitter` is set to `false` and `Delay` is specified then `Delay` will be used.
135-
- If `UseJitter` is set to `true` and `Delay` is specified then a random value is added to the `Delay`.
136-
- The random value is between -25% and +25% of `Delay`.
137-
138-
Step 2: Capping the delay if needed:
139-
140-
- If `MaxDelay` is not set then the previously calculated delay will be used.
141-
- If `MaxDelay` is set and the previously calculated delay is greater than `MaxDelay` then `MaxDelay` will be used.
142-
143-
Step 3: Using the generator if supplied
144-
145-
- If the returned `TimeSpan` of the `DelayGenerator` method call is positive then it will be used.
146-
- If the returned `TimeSpan` of the `DelayGenerator` method call is negative then it will use the step 2's result.
147-
- If the `DelayGenerator` method call is `null` then it will use the step 2's result.
148-
149-
> [!NOTE]
150-
> The `DelayGenerator`'s returned value is not capped with the `MaxDelay`.
131+
```mermaid
132+
stateDiagram-v2
133+
134+
state if_state_step1 <<choice>>
135+
state if_state_step2 <<choice>>
136+
state if_state_step3 <<choice>>
137+
138+
constant: Delay
139+
constantWJitter: Delay + Random
140+
compare: MaxDelay < BaseDelay
141+
setBase: Set BaseDelay
142+
setNormalized: Set NormalizedDelay
143+
setNext: Set NextDelay
144+
145+
UseJitter --> if_state_step1
146+
if_state_step1 --> constantWJitter:true
147+
if_state_step1 --> constant: false
148+
constantWJitter --> setBase
149+
constant --> setBase
150+
151+
setBase --> compare
152+
compare --> if_state_step2
153+
if_state_step2 --> MaxDelay: true
154+
if_state_step2 --> BaseDelay: false
155+
MaxDelay --> setNormalized
156+
BaseDelay --> setNormalized
157+
158+
setNormalized --> DelayGenerator
159+
DelayGenerator --> if_state_step3
160+
if_state_step3 --> GeneratedDelay: positive
161+
if_state_step3 --> NormalizedDelay: null or negative
162+
GeneratedDelay --> setNext
163+
NormalizedDelay --> setNext
164+
setNext --> [*]
165+
```
151166

152167
#### Constant examples
153168

154169
The delays column contains an example series of five values to depict the patterns.
155170

156-
| Settings | Delays in milliseconds |
157-
|--|--|
158-
| `Delay`: `1sec` | [1000,1000,1000,1000,1000] |
159-
| `Delay`: `1sec`, `UseJitter`: `true` | [986,912,842,972,1007] |
160-
| `Delay`: `1sec`, `UseJitter`: `true`, `MaxDelay`: `1100ms` | [1100,978,1100,1041,916] |
171+
| Settings | Delays in milliseconds |
172+
|------------------------------------------------------------|----------------------------------|
173+
| `Delay`: `1sec` | [ 1000, 1000, 1000, 1000, 1000 ] |
174+
| `Delay`: `1sec`, `UseJitter`: `true` | [ 986, 912, 842, 972, 1007 ] |
175+
| `Delay`: `1sec`, `UseJitter`: `true`, `MaxDelay`: `1100ms` | [ 1100, 978, 1100, 1041, 916 ] |
161176

162177
### Linear
163178

164-
This algorithm increases the delays for every attempt in a linear fashion if no jitter is used.
179+
```mermaid
180+
stateDiagram-v2
181+
182+
state if_state_step1 <<choice>>
183+
state if_state_step2 <<choice>>
184+
state if_state_step3 <<choice>>
185+
186+
linear: Delay * AttemptNumber
187+
linearWJitter: (Delay * AttemptNumber) + Random
188+
compare: MaxDelay < BaseDelay
189+
setBase: Set BaseDelay
190+
setNormalized: Set NormalizedDelay
191+
setNext: Set NextDelay
192+
193+
UseJitter --> if_state_step1
194+
if_state_step1 --> linearWJitter:true
195+
if_state_step1 --> linear: false
196+
linearWJitter --> setBase
197+
linear --> setBase
198+
199+
setBase --> compare
200+
compare --> if_state_step2
201+
if_state_step2 --> MaxDelay: true
202+
if_state_step2 --> BaseDelay: false
203+
MaxDelay --> setNormalized
204+
BaseDelay --> setNormalized
205+
206+
setNormalized --> DelayGenerator
207+
DelayGenerator --> if_state_step3
208+
if_state_step3 --> GeneratedDelay: positive
209+
if_state_step3 --> NormalizedDelay: null or negative
210+
GeneratedDelay --> setNext
211+
NormalizedDelay --> setNext
212+
setNext --> [*]
213+
```
165214

166-
Step 1: Calculating the base delay:
215+
#### Linear examples
167216

168-
- If `UseJitter` is set to `false` and `Delay` is specified then `Delay` multiplied by the actual attempt number will be used.
169-
- If `UseJitter` is set to `true` and `Delay` is specified then a random value is added to the `Delay` multiplied by the actual attempt number.
170-
- The random value is between -25% and +25% of the newly calculated `Delay`.
217+
The delays column contains an example series of five values to depict the patterns.
171218

172219
> [!NOTE]
173220
> Because the jitter calculation is based on the newly calculated delay, the new delay could be less than the previous value.
174221
175-
Step 2 and 3 are the same as for the Constant algorithm.
176-
177-
#### Linear examples
178-
179-
The delays column contains an example series of five values to depict the patterns.
180-
181-
| Settings | Delays in milliseconds |
182-
|--|--|
183-
| `Delay`: `1sec` | [1000,2000,3000,4000,5000] |
184-
| `Delay`: `1sec`, `UseJitter`: `true` | [1129,2147,2334,4894,4102] |
185-
| `Delay`: `1sec`, `UseJitter`: `true`, `MaxDelay`: `4500ms` | [907,2199,2869,4500,4500] |
222+
| Settings | Delays in milliseconds |
223+
|------------------------------------------------------------|----------------------------------|
224+
| `Delay`: `1sec` | [ 1000, 2000, 3000, 4000, 5000 ] |
225+
| `Delay`: `1sec`, `UseJitter`: `true` | [ 1129, 2147, 2334, 4894, 4102 ] |
226+
| `Delay`: `1sec`, `UseJitter`: `true`, `MaxDelay`: `4500ms` | [ 907, 2199, 2869, 4500, 4500 ] |
186227

187228
### Exponential
188229

189-
This algorithm increases the delays for every attempt in an exponential fashion if no jitter is used.
190-
191-
- If `UseJitter` is set to `false` and `Delay` is specified then squaring actual attempt number multiplied by the `Delay` will be used (*`attempt^2 * delay`*).
192-
- If `UseJitter` is set to `true` and the `Delay` is specified then a `DecorrelatedJitterBackoffV2` formula (based on [Polly.Contrib.WaitAndRetry](https://github.com/Polly-Contrib/Polly.Contrib.WaitAndRetry)) will be used.
193-
194-
> [!NOTE]
195-
> Because the jitter calculation is based on the newly calculated delay, the new delay could be less than the previous value.
196-
197-
Step 2 and 3 are the same as for the Constant algorithm.
230+
```mermaid
231+
stateDiagram-v2
232+
233+
state if_state_step1 <<choice>>
234+
state if_state_step2 <<choice>>
235+
state if_state_step3 <<choice>>
236+
237+
exponential: Delay * AttemptNumber^2
238+
exponentialWJitter: Decorrelated Jitter Backoff V2
239+
compare: MaxDelay < BaseDelay
240+
setBase: Set BaseDelay
241+
setNormalized: Set NormalizedDelay
242+
setNext: Set NextDelay
243+
244+
UseJitter --> if_state_step1
245+
if_state_step1 --> exponentialWJitter:true
246+
if_state_step1 --> exponential: false
247+
exponentialWJitter --> setBase
248+
exponential --> setBase
249+
250+
setBase --> compare
251+
compare --> if_state_step2
252+
if_state_step2 --> MaxDelay: true
253+
if_state_step2 --> BaseDelay: false
254+
MaxDelay --> setNormalized
255+
BaseDelay --> setNormalized
256+
257+
setNormalized --> DelayGenerator
258+
DelayGenerator --> if_state_step3
259+
if_state_step3 --> GeneratedDelay: positive
260+
if_state_step3 --> NormalizedDelay: null or negative
261+
GeneratedDelay --> setNext
262+
NormalizedDelay --> setNext
263+
setNext --> [*]
264+
```
198265

199266
#### Exponential examples
200267

201268
The delays column contains an example series of five values to depict the patterns.
202269

203-
| Settings | Delays in milliseconds |
204-
|--|--|
205-
| `Delay`: `1sec` | [1000,2000,4000,8000,16000] |
206-
| `Delay`: `1sec`, `UseJitter`: `true` | [393,1453,4235,5369,16849] |
207-
| `Delay`: `1sec`, `UseJitter`: `true`, `MaxDelay`: `15000ms` | [477,793,2227,5651,15000] |
270+
> [!NOTE]
271+
> Because the jitter calculation is based on the newly calculated delay, the new delay could be less than the previous value.
272+
273+
| Settings | Delays in milliseconds |
274+
|-------------------------------------------------------------|-----------------------------------|
275+
| `Delay`: `1sec` | [ 1000, 2000, 4000, 8000, 16000 ] |
276+
| `Delay`: `1sec`, `UseJitter`: `true` | [ 393, 1453, 4235, 5369, 16849 ] |
277+
| `Delay`: `1sec`, `UseJitter`: `true`, `MaxDelay`: `15000ms` | [ 477, 793, 2227, 5651, 15000 ] |
208278

209279
---
210280

0 commit comments

Comments
 (0)
Please sign in to comment.