diff --git a/docs/chaos/index.md b/docs/chaos/index.md index 25458bbf2b2..05448f50969 100644 --- a/docs/chaos/index.md +++ b/docs/chaos/index.md @@ -66,7 +66,7 @@ Chaos strategies (formerly known as Monkey strategies) are in essence a [Resilie | [Fault](fault.md) | No | Injects exceptions in your system. | | [Outcome](outcome.md) | Yes | Injects fake outcomes (results or exceptions) in your system. | | [Latency](latency.md) | No | Injects latency into executions before the calls are made. | -| [Behavior](behavior.md) | No | Allows you to inject *any* extra behaviour, before a call is placed. | +| [Behavior](behavior.md) | No | Allows you to inject *any* extra behavior, before a call is placed. | ## Common options across strategies @@ -85,6 +85,8 @@ All the strategies' options implement the [`ChaosStrategyOptions`](xref:Polly.Si | `EnabledGenerator` | `null` | The generator that indicates whether the chaos strategy is enabled for a given execution. | > [!NOTE] +> If both `InjectionRate` and `InjectionRateGenerator` are specified then `InjectionRate` will be ignored. +> > If both `Enabled` and `EnabledGenerator` are specified then `Enabled` will be ignored. [simmy]: https://github.com/Polly-Contrib/Simmy diff --git a/docs/strategies/circuit-breaker.md b/docs/strategies/circuit-breaker.md index 50798e3b451..fdd744c7f8c 100644 --- a/docs/strategies/circuit-breaker.md +++ b/docs/strategies/circuit-breaker.md @@ -105,6 +105,9 @@ new ResiliencePipelineBuilder().AddCircuitBreaker(optionsSt | `ManualControl` | `null` | Allows for manual control to isolate or close the circuit. | | `StateProvider` | `null` | Enables the retrieval of the current state of the circuit. | +> [!NOTE] +> If both `BreakDuration` and `BreakDurationGenerator` are specified then `BreakDuration` will be ignored. + ## Diagrams ### State diagram diff --git a/docs/strategies/hedging.md b/docs/strategies/hedging.md index 9348f308850..20b5674f07d 100644 --- a/docs/strategies/hedging.md +++ b/docs/strategies/hedging.md @@ -60,12 +60,12 @@ new ResiliencePipelineBuilder().AddHedging(optionsDefaults) ## Defaults | Property | Default Value | Description | -| ------------------- | -------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | +|---------------------|----------------------------------------------------------------------------|------------------------------------------------------------------------------------------| | `ShouldHandle` | Predicate that handles all exceptions except `OperationCanceledException`. | Predicate that determines what results and exceptions are handled by the retry strategy. | | `MaxHedgedAttempts` | 1 | The maximum number of hedged actions to use, in addition to the original action. | | `Delay` | 2 seconds | The maximum waiting time before spawning a new hedged action. | | `ActionGenerator` | Returns the original callback that was passed to the hedging strategy. | Generator that creates hedged actions. | -| `DelayGenerator` | `null` | Used for generating custom delays for hedging. If `null` then `Delay` is used. | +| `DelayGenerator` | `null` | Used for generating custom delays for hedging. | | `OnHedging` | `null` | Event that is raised when a hedging is performed. | You can use the following special values for `Delay` or in `DelayGenerator`: @@ -73,6 +73,9 @@ You can use the following special values for `Delay` or in `DelayGenerator`: - `0 seconds` - the hedging strategy immediately creates a total of `MaxHedgedAttempts` and completes when the fastest acceptable result is available. - `-1 millisecond` - this value indicates that the strategy does not create a new hedged task before the previous one completes. This enables scenarios where having multiple concurrent hedged tasks can cause side effects. +> [!NOTE] +> If both `Delay` and `DelayGenerator` are specified then `Delay` will be ignored. + ## Concurrency modes In the sections below, explore the different concurrency modes available in the hedging strategy. The behavior is primarily controlled by the `Delay` property value. diff --git a/docs/strategies/retry.md b/docs/strategies/retry.md index 12e94f1db8e..262febffd62 100644 --- a/docs/strategies/retry.md +++ b/docs/strategies/retry.md @@ -108,6 +108,110 @@ new ResiliencePipelineBuilder().AddRetry(optionsExtractDela | `OnRetry` | `null` | Action executed when retry occurs. | | `MaxDelay` | `null` | Caps the calculated retry delay to a specified maximum duration. | +## Calculation of the next delay + +If the `ShouldHandle` predicate returns `true` and the next attempt number is not greater than `MaxRetryAttempts` then the retry strategy calculates the next delay. + +There are many properties that may contribute to this calculation: + +- `BackoffType`: Specifies which calculation algorithm should run. +- `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*. +- `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. +- `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. +- `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. + +> [!IMPORTANT] +> The summarized description below is an implementation detail. It may change in the future without notice. + +The `BackoffType` property's data type is the [`DelayBackoffType`](xref:Polly.DelayBackoffType) enumeration. This primarily controls how the calculation is done. + +### Constant + +Even though the `Constant` name could imply that only the `Delay` property is used, in reality all the above listed properties are used. + +Step 1: Calculating the base delay: + +- If `UseJitter` is set to `false` and `Delay` is specified then `Delay` will be used. +- If `UseJitter` is set to `true` and `Delay` is specified then a random value is added to the `Delay`. + - The random value is between -25% and +25% of `Delay`. + +Step 2: Capping the delay if needed: + +- If `MaxDelay` is not set then the previously calculated delay will be used. +- If `MaxDelay` is set and the previously calculated delay is greater than `MaxDelay` then `MaxDelay` will be used. + +Step 3: Using the generator if supplied + +- If the returned `TimeSpan` of the `DelayGenerator` method call is positive then it will be used. +- If the returned `TimeSpan` of the `DelayGenerator` method call is negative then it will use the step 2's result. +- If the `DelayGenerator` method call is `null` then it will use the step 2's result. + +> [!NOTE] +> The `DelayGenerator`'s returned value is not capped with the `MaxDelay`. + +#### Constant examples + +The delays column contains an example series of five values to depict the patterns. + +| Settings | Delays in milliseconds | +|--|--| +| `Delay`: `1sec` | [1000,1000,1000,1000,1000] | +| `Delay`: `1sec`, `UseJitter`: `true` | [986,912,842,972,1007] | +| `Delay`: `1sec`, `UseJitter`: `true`, `MaxDelay`: `1100ms` | [1100,978,1100,1041,916] | + +### Linear + +This algorithm increases the delays for every attempt in a linear fashion if no jitter is used. + +Step 1: Calculating the base delay: + +- If `UseJitter` is set to `false` and `Delay` is specified then `Delay` multiplied by the actual attempt number will be used. +- 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. + - The random value is between -25% and +25% of the newly calculated `Delay`. + +> [!NOTE] +> Because the jitter calculation is based on the newly calculated delay, the new delay could be less than the previous value. + +Step 2 and 3 are the same as for the Constant algorithm. + +#### Linear examples + +The delays column contains an example series of five values to depict the patterns. + +| Settings | Delays in milliseconds | +|--|--| +| `Delay`: `1sec` | [1000,2000,3000,4000,5000] | +| `Delay`: `1sec`, `UseJitter`: `true` | [1129,2147,2334,4894,4102] | +| `Delay`: `1sec`, `UseJitter`: `true`, `MaxDelay`: `4500ms` | [907,2199,2869,4500,4500] | + +### Exponential + +This algorithm increases the delays for every attempt in an exponential fashion if no jitter is used. + +- 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`*). +- 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. + +> [!NOTE] +> Because the jitter calculation is based on the newly calculated delay, the new delay could be less than the previous value. + +Step 2 and 3 are the same as for the Constant algorithm. + +#### Exponential examples + +The delays column contains an example series of five values to depict the patterns. + +| Settings | Delays in milliseconds | +|--|--| +| `Delay`: `1sec` | [1000,2000,4000,8000,16000] | +| `Delay`: `1sec`, `UseJitter`: `true` | [393,1453,4235,5369,16849] | +| `Delay`: `1sec`, `UseJitter`: `true`, `MaxDelay`: `15000ms` | [477,793,2227,5651,15000] | + +--- + +> [!TIP] +> For more details please check out the [`RetryHelper`](https://github.com/App-vNext/Polly/blob/main/src/Polly.Core/Retry/RetryHelper.cs) +> and the [`RetryResilienceStrategy`](https://github.com/App-vNext/Polly/blob/main/src/Polly.Core/Retry/RetryResilienceStrategy.cs) classes. + ## Diagrams Let's suppose we have a retry strategy with `MaxRetryAttempts`: `2`. diff --git a/docs/strategies/timeout.md b/docs/strategies/timeout.md index 0dab983eccb..961a1e6bb45 100644 --- a/docs/strategies/timeout.md +++ b/docs/strategies/timeout.md @@ -125,6 +125,9 @@ The `OnTimeout` delegate can be useful when you define a resilience pipeline whi | `TimeoutGenerator` | `null` | Generates the timeout for a given execution. | | `OnTimeout` | `null` | Event that is raised when timeout occurs. | +> [!NOTE] +> If both `Timeout` and `TimeoutGenerator` are specified then `Timeout` will be ignored. + ## Diagrams ### Happy path sequence diagram