diff --git a/README_V8.md b/README_V8.md
index 90b2c9d2c7a..631b7082858 100644
--- a/README_V8.md
+++ b/README_V8.md
@@ -111,12 +111,12 @@ Polly categorizes resilience strategies into two main groups:
| Strategy | Reactive | Premise | AKA | How does the strategy mitigate?|
| ------------- | --- | ------------- |:-------------: |------------- |
-|**Retry**
(strategy family)
([quickstart](#retry) ; [deep](https://github.com/App-vNext/Polly/wiki/Retry)) |Yes|Many faults are transient and may self-correct after a short delay.| *Maybe it's just a blip* | Allows configuring automatic retries. |
-|**Circuit-breaker**
(strategy family)
([quickstart](#circuit-breaker) ; [deep](https://github.com/App-vNext/Polly/wiki/Circuit-Breaker))|Yes|When a system is seriously struggling, failing fast is better than making users/callers wait.
Protecting a faulting system from overload can help it recover. | *Stop doing it if it hurts*
*Give that system a break* | Breaks the circuit (blocks executions) for a period, when faults exceed some pre-configured threshold. |
-|**Timeout**
([quickstart](#timeout) ; [deep](https://github.com/App-vNext/Polly/wiki/Timeout))|No|Beyond a certain wait, a success result is unlikely.| *Don't wait forever* |Guarantees the caller won't have to wait beyond the timeout. |
-|**Rate Limiter**
([quickstart](#rate-limiter) ; [deep](https://github.com/App-vNext/Polly/wiki/Rate-Limit))|No|Limiting the rate a system handles requests is another way to control load.
This can apply to the way your system accepts incoming calls, and/or to the way you call downstream services. | *Slow down a bit, will you?* |Constrains executions to not exceed a certain rate. |
-|**Fallback**
([quickstart](#fallback) ; [deep](https://github.com/App-vNext/Polly/wiki/Fallback))|Yes|Things will still fail - plan what you will do when that happens.| *Degrade gracefully* |Defines an alternative value to be returned (or action to be executed) on failure. |
-|**Hedging**
([quickstart](#hedging) ; [deep](https://github.com/App-vNext/Polly/wiki/TODO))|Yes|Things can be slow sometimes, plan what you will do when that happens.| *Hedge your bets* | Executes parallel actions when things are slow and waits for the fastest one. |
+|**Retry**
(strategy family)
([quickstart](#retry) ; [deep](docs/strategies/retry.md)) |Yes|Many faults are transient and may self-correct after a short delay.| *Maybe it's just a blip* | Allows configuring automatic retries. |
+|**Circuit-breaker**
(strategy family)
([quickstart](#circuit-breaker) ; [deep](docs/strategies/circuit-breaker.md))|Yes|When a system is seriously struggling, failing fast is better than making users/callers wait.
Protecting a faulting system from overload can help it recover. | *Stop doing it if it hurts*
*Give that system a break* | Breaks the circuit (blocks executions) for a period, when faults exceed some pre-configured threshold. |
+|**Timeout**
([quickstart](#timeout) ; [deep](docs/strategies/timeout.md))|No|Beyond a certain wait, a success result is unlikely.| *Don't wait forever* |Guarantees the caller won't have to wait beyond the timeout. |
+|**Rate Limiter**
([quickstart](#rate-limiter) ; [deep](docs/strategies/rate-limiter.md))|No|Limiting the rate a system handles requests is another way to control load.
This can apply to the way your system accepts incoming calls, and/or to the way you call downstream services. | *Slow down a bit, will you?* |Constrains executions to not exceed a certain rate. |
+|**Fallback**
([quickstart](#fallback) ; [deep](docs/strategies/fallback.md))|Yes|Things will still fail - plan what you will do when that happens.| *Degrade gracefully* |Defines an alternative value to be returned (or action to be executed) on failure. |
+|**Hedging**
([quickstart](#hedging) ; [deep](docs/strategies/hedging.md))|Yes|Things can be slow sometimes, plan what you will do when that happens.| *Hedge your bets* | Executes parallel actions when things are slow and waits for the fastest one. |
Visit [resilience strategies](docs/resilience-strategies.md) docs to explore how to configure individual resilience strategies in more detail.
@@ -124,7 +124,8 @@ Visit [resilience strategies](docs/resilience-strategies.md) docs to explore how
```cs
-// Add retry using the default options
+// Add retry using the default options.
+// See https://github.com/App-vNext/Polly/blob/main/docs/strategies/retry.md#defaults for default values.
new ResiliencePipelineBuilder().AddRetry(new RetryStrategyOptions());
// For instant retries with no delay
@@ -200,13 +201,14 @@ new ResiliencePipelineBuilder().AddRetry(new RetryStrategyOptions
```
-If all retries fail, a retry strategy rethrows the final exception back to the calling code. For more details visit the [retry strategy documentation](https://github.com/App-vNext/Polly/wiki/Retry).
+If all retries fail, a retry strategy rethrows the final exception back to the calling code. For more details visit the [retry strategy documentation](docs/strategies/retry.md).
### Circuit Breaker
```cs
// Add circuit breaker with default options.
+// See https://github.com/App-vNext/Polly/blob/main/docs/strategies/circuit-breaker.md#defaults for default values.
new ResiliencePipelineBuilder().AddCircuitBreaker(new CircuitBreakerStrategyOptions());
// Add circuit breaker with customized options:
@@ -260,23 +262,13 @@ await manualControl.CloseAsync();
```
-The Circuit Breaker strategy prevents execution by throwing a `BrokenCircuitException` when the circuit is open. For more details, refer to the [Circuit-Breaker documentation on GitHub](https://github.com/App-vNext/Polly/wiki/Advanced-Circuit-Breaker).
-
-> [!NOTE]
-> Be aware that the Circuit Breaker strategy [rethrows all exceptions](https://github.com/App-vNext/Polly/wiki/Circuit-Breaker#exception-handling), including those that are handled. A Circuit Breaker's role is to monitor faults and break the circuit when a certain threshold is reached; it does not manage retries. Combine the Circuit Breaker with a Retry strategy if needed.
-
-For more insights on the Circuit Breaker pattern, you can visit:
-
-- [Making the Netflix API More Resilient](https://techblog.netflix.com/2011/12/making-netflix-api-more-resilient.html)
-- [Circuit Breaker by Martin Fowler](https://martinfowler.com/bliki/CircuitBreaker.html)
-- [Circuit Breaker Pattern by Microsoft](https://msdn.microsoft.com/en-us/library/dn589784.aspx)
-- [Original Circuit Breaking Article](https://web.archive.org/web/20160106203951/http://thatextramile.be/blog/2008/05/the-circuit-breaker)
+For more details, refer to the [Circuit-Breaker documentation](docs/strategies/circuit-breaker.md).
### Fallback
```cs
-// Use a fallback/substitute value if an operation fails.
+// Add a fallback/substitute value if an operation fails.
new ResiliencePipelineBuilder()
.AddFallback(new FallbackStrategyOptions
{
@@ -321,18 +313,19 @@ new ResiliencePipelineBuilder()
```
-For more details, refer to the [Fallback documentation](https://github.com/App-vNext/Polly/wiki/Fallback).
+For more details, refer to the [Fallback documentation](docs/strategies/fallback.md).
### Hedging
```cs
// Add hedging with default options.
+// See https://github.com/App-vNext/Polly/blob/main/docs/strategies/hedging.md#defaults for default values.
new ResiliencePipelineBuilder()
.AddHedging(new HedgingStrategyOptions());
// Add a customized hedging strategy that retries up to 3 times if the execution
-// takes longer than 1 second or if it fails due to an exception or returns an HTTP 500 Internal Server Error.
+// takes longer than 1 second or if it fails due to an exception or returns an HTTP 500 Internal Server Error.
new ResiliencePipelineBuilder()
.AddHedging(new HedgingStrategyOptions
{
@@ -364,7 +357,7 @@ new ResiliencePipelineBuilder()
```
-If all hedged attempts fail, the hedging strategy will either re-throw the last exception or return the final failed result to the caller. For more information, refer to the [hedging strategy documentation](docs/hedging.md).
+If all hedged attempts fail, the hedging strategy will either re-throw the last exception or return the final failed result to the caller. For more information, refer to the [hedging strategy documentation](docs/strategies/hedging.md).
### Timeout
@@ -372,7 +365,8 @@ The timeout resilience strategy assumes delegates you execute support [co-operat
```cs
-// To add timeout using the default options
+// Add timeout using the default options.
+// See https://github.com/App-vNext/Polly/blob/main/docs/strategies/timeout.md#defaults for default values.
new ResiliencePipelineBuilder()
.AddTimeout(new TimeoutStrategyOptions());
@@ -409,31 +403,14 @@ new ResiliencePipelineBuilder()
```
-Example execution:
-
-
-```cs
-var pipeline = new ResiliencePipelineBuilder()
- .AddTimeout(TimeSpan.FromSeconds(3))
- .Build();
-
-HttpResponseMessage httpResponse = await pipeline.ExecuteAsync(
- async ct =>
- {
- // Execute a delegate that takes a CancellationToken as an input parameter.
- return await httpClient.GetAsync(endpoint, ct);
- },
- cancellationToken);
-```
-
-
-Timeout strategies throw `TimeoutRejectedException` when a timeout occurs. For more details see [Timeout strategy documentation](https://github.com/App-vNext/Polly/wiki/Timeout).
+Timeout strategies throw `TimeoutRejectedException` when a timeout occurs. For more details see [Timeout strategy documentation](docs/strategies/timeout.md).
### Rate Limiter
```cs
// Add rate limiter with default options.
+// See https://github.com/App-vNext/Polly/blob/main/docs/strategies/rate-limiter.md#defaults for default values.
new ResiliencePipelineBuilder()
.AddRateLimiter(new RateLimiterStrategyOptions());
@@ -475,32 +452,7 @@ new ResiliencePipelineBuilder()
```
-Example execution:
-
-
-```cs
-var pipeline = new ResiliencePipelineBuilder().AddConcurrencyLimiter(100, 50).Build();
-
-try
-{
- // Execute an asynchronous text search operation.
- var result = await pipeline.ExecuteAsync(
- token => TextSearchAsync(query, token),
- cancellationToken);
-}
-catch (RateLimiterRejectedException ex)
-{
- // Handle RateLimiterRejectedException,
- // that can optionally contain information about when to retry.
- if (ex.RetryAfter is TimeSpan retryAfter)
- {
- Console.WriteLine($"Retry After: {retryAfter}");
- }
-}
-```
-
-
-Rate limiter strategy throws `RateLimiterRejectedException` if execution is rejected. For more details see [Rate Limiter strategy documentation](https://github.com/App-vNext/Polly/wiki/Rate-Limit).
+Rate limiter strategy throws `RateLimiterRejectedException` if execution is rejected. For more details see [Rate Limiter strategy documentation](docs/strategies/rate-limiter.md).
## Next steps
diff --git a/docs/README.md b/docs/README.md
index 6b049870656..c05f917518a 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -2,6 +2,15 @@
If you're already familiar with the [basic features](../README.md) of Polly, delve deeper into its advanced functionalities here.
+## Resilience strategies
+
+- [Retry](strategies/retry.md): Allows for the automated re-execution of failed operations according to predefined conditions.
+- [Circuit Breaker](strategies/circuit-breaker.md): Temporarily halts all operations when a defined threshold of failures is exceeded, in order to prevent further issues.
+- [Fallback](strategies/fallback.md): Provides a backup value or executes an alternative action when the primary operation fails, ensuring graceful degradation.
+- [Hedging](strategies/hedging.md): Initiates multiple identical operations in parallel when performance lags, and returns the result of the fastest-completing operation.
+- [Timeout](strategies/timeout.md): Sets a maximum time limit for an operation to complete, preventing indefinite waiting.
+- [Rate Limiter](strategies/rate-limiter.md): Regulates the frequency of operations to ensure they do not exceed a set rate, thereby maintaining system stability.
+
## Topics
- [General](general.md): General information about Polly.
diff --git a/docs/strategies/circuit-breaker.md b/docs/strategies/circuit-breaker.md
new file mode 100644
index 00000000000..a4a267db7e6
--- /dev/null
+++ b/docs/strategies/circuit-breaker.md
@@ -0,0 +1,99 @@
+# Circuit breaker resilience strategy
+
+## About
+
+- **Options**:
+ - [`CircuitBreakerStrategyOptions`](../../src/Polly.Core/CircuitBreaker/CircuitBreakerStrategyOptions.cs)
+ - [`CircuitBreakerStrategyOptions`](../../src/Polly.Core/CircuitBreaker/CircuitBreakerStrategyOptions.TResult.cs)
+- **Extensions**: `AddCircuitBreaker`
+- **Strategy Type**: Reactive
+- **Exceptions**:
+ - `BrokenCircuitException`: Thrown when a circuit is broken and the action could not be executed.
+ - `IsolatedCircuitException`: Thrown when a circuit is isolated (held open) by manual override.
+
+> [!NOTE]
+> Version 8 documentation for this strategy has not yet been migrated. For more information on circuit breaker concepts and behavior, refer to the [older documentation](https://github.com/App-vNext/Polly/wiki/Circuit-Breaker).
+
+> [!NOTE]
+> Be aware that the Circuit Breaker strategy [rethrows all exceptions](https://github.com/App-vNext/Polly/wiki/Circuit-Breaker#exception-handling), including those that are handled. A Circuit Breaker's role is to monitor faults and break the circuit when a certain threshold is reached; it does not manage retries. Combine the Circuit Breaker with a Retry strategy if needed.
+
+## Usage
+
+
+```cs
+// Add circuit breaker with default options.
+// See https://github.com/App-vNext/Polly/blob/main/docs/strategies/circuit-breaker.md#defaults for default values.
+new ResiliencePipelineBuilder().AddCircuitBreaker(new CircuitBreakerStrategyOptions());
+
+// Add circuit breaker with customized options:
+//
+// The circuit will break if more than 50% of actions result in handled exceptions,
+// within any 10-second sampling duration, and at least 8 actions are processed.
+new ResiliencePipelineBuilder().AddCircuitBreaker(new CircuitBreakerStrategyOptions
+{
+ FailureRatio = 0.5,
+ SamplingDuration = TimeSpan.FromSeconds(10),
+ MinimumThroughput = 8,
+ BreakDuration = TimeSpan.FromSeconds(30),
+ ShouldHandle = new PredicateBuilder().Handle()
+});
+
+// Handle specific failed results for HttpResponseMessage:
+new ResiliencePipelineBuilder()
+ .AddCircuitBreaker(new CircuitBreakerStrategyOptions
+ {
+ ShouldHandle = new PredicateBuilder()
+ .Handle()
+ .HandleResult(response => response.StatusCode == HttpStatusCode.InternalServerError)
+ });
+
+// Monitor the circuit state, useful for health reporting:
+var stateProvider = new CircuitBreakerStateProvider();
+
+new ResiliencePipelineBuilder()
+ .AddCircuitBreaker(new() { StateProvider = stateProvider })
+ .Build();
+
+/*
+CircuitState.Closed - Normal operation; actions are executed.
+CircuitState.Open - Circuit is open; actions are blocked.
+CircuitState.HalfOpen - Recovery state after break duration expires; actions are permitted.
+CircuitState.Isolated - Circuit is manually held open; actions are blocked.
+*/
+
+// Manually control the Circuit Breaker state:
+var manualControl = new CircuitBreakerManualControl();
+
+new ResiliencePipelineBuilder()
+ .AddCircuitBreaker(new() { ManualControl = manualControl })
+ .Build();
+
+// Manually isolate a circuit, e.g., to isolate a downstream service.
+await manualControl.IsolateAsync();
+
+// Manually close the circuit to allow actions to be executed again.
+await manualControl.CloseAsync();
+```
+
+
+## Defaults
+
+| Property | Default Value | Description |
+| ------------------- | -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
+| `ShouldHandle` | Predicate that handles all exceptions except `OperationCanceledException`. | Specifies which results and exceptions are managed by the circuit breaker strategy. |
+| `FailureRatio` | 0.1 | The ratio of failures to successes that will cause the circuit to break/open. |
+| `MinimumThroughput` | 100 | The minimum number of actions that must occur in the circuit within a specific time slice. |
+| `SamplingDuration` | 30 seconds | The time period over which failure ratios are calculated. |
+| `BreakDuration` | 5 seconds | The time period for which the circuit will remain broken/open before attempting to reset. |
+| `OnClosed` | `null` | Event triggered when the circuit transitions to the `Closed` state. |
+| `OnOpened` | `null` | Event triggered when the circuit transitions to the `Opened` state. |
+| `OnHalfOpened` | `null` | Event triggered when the circuit transitions to the `HalfOpened` state. |
+| `ManualControl` | `null` | Allows for manual control to isolate or close the circuit. |
+| `StateProvider` | `null` | Enables the retrieval of the current state of the circuit. |
+
+## Resources
+
+- [Making the Netflix API More Resilient](https://techblog.netflix.com/2011/12/making-netflix-api-more-resilient.html)
+- [Circuit Breaker by Martin Fowler](https://martinfowler.com/bliki/CircuitBreaker.html)
+- [Circuit Breaker Pattern by Microsoft](https://msdn.microsoft.com/en-us/library/dn589784.aspx)
+- [Original Circuit Breaking Article](https://web.archive.org/web/20160106203951/http://thatextramile.be/blog/2008/05/the-circuit-breaker)
diff --git a/docs/strategies/fallback.md b/docs/strategies/fallback.md
new file mode 100644
index 00000000000..fa51af2c582
--- /dev/null
+++ b/docs/strategies/fallback.md
@@ -0,0 +1,67 @@
+# Fallback resilience strategy
+
+## About
+
+- **Options**: [`FallbackStrategyOptions`](../../src/Polly.Core/Fallback/FallbackStrategyOptions.TResult.cs)
+- **Extensions**: `AddFallback`
+- **Strategy Type**: Reactive
+
+> [!NOTE]
+> Version 8 documentation for this strategy has not yet been migrated. For more information on fallback concepts and behavior, refer to the [older documentation](https://github.com/App-vNext/Polly/wiki/Fallback).
+
+## Usage
+
+
+```cs
+// Add a fallback/substitute value if an operation fails.
+new ResiliencePipelineBuilder()
+ .AddFallback(new FallbackStrategyOptions
+ {
+ ShouldHandle = new PredicateBuilder()
+ .Handle()
+ .HandleResult(r => r is null),
+ FallbackAction = args => Outcome.FromResultAsValueTask(UserAvatar.Blank)
+ });
+
+// Use a dynamically generated value if an operation fails.
+new ResiliencePipelineBuilder()
+ .AddFallback(new FallbackStrategyOptions
+ {
+ ShouldHandle = new PredicateBuilder()
+ .Handle()
+ .HandleResult(r => r is null),
+ FallbackAction = args =>
+ {
+ var avatar = UserAvatar.GetRandomAvatar();
+ return Outcome.FromResultAsValueTask(avatar);
+ }
+ });
+
+// Use a default or dynamically generated value, and execute an additional action if the fallback is triggered.
+new ResiliencePipelineBuilder()
+ .AddFallback(new FallbackStrategyOptions
+ {
+ ShouldHandle = new PredicateBuilder()
+ .Handle()
+ .HandleResult(r => r is null),
+ FallbackAction = args =>
+ {
+ var avatar = UserAvatar.GetRandomAvatar();
+ return Outcome.FromResultAsValueTask(UserAvatar.Blank);
+ },
+ OnFallback = args =>
+ {
+ // Add extra logic to be executed when the fallback is triggered, such as logging.
+ return default; // returns an empty ValueTask
+ }
+ });
+```
+
+
+## Defaults
+
+| Property | Default Value | Description |
+| ---------------- | -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
+| `ShouldHandle` | Predicate that handles all exceptions except `OperationCanceledException`. | Predicate that determines what results and exceptions are handled by the fallback strategy. |
+| `FallbackAction` | `Null`, **Required** | Fallback action to be executed. |
+| `OnFallback` | `null` | Event that is raised when fallback happens. |
diff --git a/docs/strategies/hedging.md b/docs/strategies/hedging.md
new file mode 100644
index 00000000000..f2479f3eff2
--- /dev/null
+++ b/docs/strategies/hedging.md
@@ -0,0 +1,62 @@
+# Hedging resilience strategy
+
+## About
+
+- **Options**: [`HedgingStrategyOptions`](../../src/Polly.Core/Hedging/HedgingStrategyOptions.TResult.cs)
+- **Extensions**: `AddHedging`
+- **Strategy Type**: Reactive
+
+> 🚧 This documentation is being written as part of the Polly v8 release.
+
+## Usage
+
+
+```cs
+// Add hedging with default options.
+// See https://github.com/App-vNext/Polly/blob/main/docs/strategies/hedging.md#defaults for default values.
+new ResiliencePipelineBuilder()
+ .AddHedging(new HedgingStrategyOptions());
+
+// Add a customized hedging strategy that retries up to 3 times if the execution
+// takes longer than 1 second or if it fails due to an exception or returns an HTTP 500 Internal Server Error.
+new ResiliencePipelineBuilder()
+ .AddHedging(new HedgingStrategyOptions
+ {
+ ShouldHandle = new PredicateBuilder()
+ .Handle()
+ .HandleResult(response => response.StatusCode == HttpStatusCode.InternalServerError),
+ MaxHedgedAttempts = 3,
+ Delay = TimeSpan.FromSeconds(1),
+ ActionGenerator = args =>
+ {
+ Console.WriteLine("Preparing to execute hedged action.");
+
+ // Return a delegate function to invoke the original action with the action context.
+ // Optionally, you can also create a completely new action to be executed.
+ return () => args.Callback(args.ActionContext);
+ }
+ });
+
+// Subscribe to hedging events.
+new ResiliencePipelineBuilder()
+ .AddHedging(new HedgingStrategyOptions
+ {
+ OnHedging = args =>
+ {
+ Console.WriteLine($"OnHedging: Attempt number {args.AttemptNumber}");
+ return default;
+ }
+ });
+```
+
+
+## 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. |
+| `OnHedging` | `null` | Event that is raised when a hedging is performed. |
diff --git a/docs/strategies/rate-limiter.md b/docs/strategies/rate-limiter.md
new file mode 100644
index 00000000000..3a08dd71a9c
--- /dev/null
+++ b/docs/strategies/rate-limiter.md
@@ -0,0 +1,92 @@
+# Rate limiter resilience strategy
+
+## About
+
+- **Options**: [`RateLimiterStrategyOptions`](../../src/Polly.RateLimiting/RateLimiterStrategyOptions.cs)
+- **Extensions**: `AddRateLimiter`, `AddConcurrencyLimiter`
+- **Strategy Type**: Proactive
+- **Exceptions**:
+ - `RateLimiterRejectedException`: Thrown when a rate limiter rejects an execution.
+- **Package**: [Polly.RateLimiting](https://www.nuget.org/packages/Polly.RateLimiting)
+
+> 🚧 This documentation is being written as part of the Polly v8 release.
+
+## Usage
+
+
+```cs
+// Add rate limiter with default options.
+// See https://github.com/App-vNext/Polly/blob/main/docs/strategies/rate-limiter.md#defaults for default values.
+new ResiliencePipelineBuilder()
+ .AddRateLimiter(new RateLimiterStrategyOptions());
+
+// Create a rate limiter to allow a maximum of 100 concurrent executions and a queue of 50.
+new ResiliencePipelineBuilder()
+ .AddConcurrencyLimiter(100, 50);
+
+// Create a rate limiter that allows 100 executions per minute.
+new ResiliencePipelineBuilder()
+ .AddRateLimiter(new SlidingWindowRateLimiter(new SlidingWindowRateLimiterOptions
+ {
+ PermitLimit = 100,
+ Window = TimeSpan.FromMinutes(1)
+ }));
+
+// Create a custom partitioned rate limiter.
+var partitionedLimiter = PartitionedRateLimiter.Create(context =>
+{
+ // Extract the partition key.
+ string partitionKey = GetPartitionKey(context);
+
+ return RateLimitPartition.GetConcurrencyLimiter(
+ partitionKey,
+ key => new ConcurrencyLimiterOptions
+ {
+ PermitLimit = 100
+ });
+});
+
+new ResiliencePipelineBuilder()
+ .AddRateLimiter(new RateLimiterStrategyOptions
+ {
+ // Provide a custom rate limiter delegate.
+ RateLimiter = args =>
+ {
+ return partitionedLimiter.AcquireAsync(args.Context, 1, args.Context.CancellationToken);
+ }
+ });
+```
+
+
+Example execution:
+
+
+```cs
+var pipeline = new ResiliencePipelineBuilder().AddConcurrencyLimiter(100, 50).Build();
+
+try
+{
+ // Execute an asynchronous text search operation.
+ var result = await pipeline.ExecuteAsync(
+ token => TextSearchAsync(query, token),
+ cancellationToken);
+}
+catch (RateLimiterRejectedException ex)
+{
+ // Handle RateLimiterRejectedException,
+ // that can optionally contain information about when to retry.
+ if (ex.RetryAfter is TimeSpan retryAfter)
+ {
+ Console.WriteLine($"Retry After: {retryAfter}");
+ }
+}
+```
+
+
+## Defaults
+
+| Property | Default Value | Description |
+| --------------------------- | ---------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
+| `RateLimiter` | `null` | Generator that creates a `RateLimitLease` for executions. |
+| `DefaultRateLimiterOptions` | `PermitLimit` set to 1000 and `QueueLimit` set to 0. | The options for the default concurrency limiter that will be used when `RateLimiter` is `null`. |
+| `OnRejected` | `null` | Event that is raised when the execution is rejected by the rate limiter. |
diff --git a/docs/strategies/retry.md b/docs/strategies/retry.md
new file mode 100644
index 00000000000..8ca731a9091
--- /dev/null
+++ b/docs/strategies/retry.md
@@ -0,0 +1,105 @@
+# Retry resilience strategy
+
+## About
+
+- **Options**:
+ - [`RetryStrategyOptions`](../../src/Polly.Core/Retry/RetryStrategyOptions.cs)
+ - [`RetryStrategyOptions`](../../src/Polly.Core/Retry/RetryStrategyOptions.TResult.cs)
+- **Extensions**: `AddRetry`
+- **Strategy Type**: Reactive
+
+> [!NOTE]
+> Version 8 documentation for this strategy has not yet been migrated. For more information on retry concepts and behavior, refer to the [older documentation](https://github.com/App-vNext/Polly/wiki/Retry).
+
+## Usage
+
+
+```cs
+// Add retry using the default options.
+// See https://github.com/App-vNext/Polly/blob/main/docs/strategies/retry.md#defaults for default values.
+new ResiliencePipelineBuilder().AddRetry(new RetryStrategyOptions());
+
+// For instant retries with no delay
+new ResiliencePipelineBuilder().AddRetry(new RetryStrategyOptions
+{
+ Delay = TimeSpan.Zero
+});
+
+// For advanced control over the retry behavior, including the number of attempts,
+// delay between retries, and the types of exceptions to handle.
+new ResiliencePipelineBuilder().AddRetry(new RetryStrategyOptions
+{
+ ShouldHandle = new PredicateBuilder().Handle(),
+ BackoffType = DelayBackoffType.Exponential,
+ UseJitter = true, // Adds a random factor to the delay
+ MaxRetryAttempts = 4,
+ Delay = TimeSpan.FromSeconds(3),
+});
+
+// To use a custom function to generate the delay for retries
+new ResiliencePipelineBuilder().AddRetry(new RetryStrategyOptions
+{
+ MaxRetryAttempts = 2,
+ DelayGenerator = args =>
+ {
+ var delay = args.AttemptNumber switch
+ {
+ 0 => TimeSpan.Zero,
+ 1 => TimeSpan.FromSeconds(1),
+ _ => TimeSpan.FromSeconds(5)
+ };
+
+ // This example uses a synchronous delay generator,
+ // but the API also supports asynchronous implementations.
+ return new ValueTask(delay);
+ }
+});
+
+// To extract the delay from the result object
+new ResiliencePipelineBuilder().AddRetry(new RetryStrategyOptions
+{
+ DelayGenerator = args =>
+ {
+ if (args.Outcome.Result is HttpResponseMessage responseMessage &&
+ TryGetDelay(responseMessage, out TimeSpan delay))
+ {
+ return new ValueTask(delay);
+ }
+
+ // Returning null means the retry strategy will use its internal delay for this attempt.
+ return new ValueTask((TimeSpan?)null);
+ }
+});
+
+// To get notifications when a retry is performed
+new ResiliencePipelineBuilder().AddRetry(new RetryStrategyOptions
+{
+ MaxRetryAttempts = 2,
+ OnRetry = args =>
+ {
+ Console.WriteLine("OnRetry, Attempt: {0}", args.AttemptNumber);
+
+ // Event handlers can be asynchronous; here, we return an empty ValueTask.
+ return default;
+ }
+});
+
+// To keep retrying indefinitely until successful
+new ResiliencePipelineBuilder().AddRetry(new RetryStrategyOptions
+{
+ MaxRetryAttempts = int.MaxValue,
+});
+```
+
+
+## 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. |
+| `MaxRetryAttempts` | 3 | The maximum number of retries to use, in addition to the original call. |
+| `Delay` | 2 seconds | The base delay between retries. |
+| `BackoffType` | Constant | The type of the back-off used to generate the retry delay. |
+| `UseJitter` | False | Allows adding jitter to retry delays. |
+| `DelayGenerator` | `null` | Used for generating custom delays for retries. |
+| `OnRetry` | `null` | Action executed when retry occurs. |
diff --git a/docs/strategies/timeout.md b/docs/strategies/timeout.md
new file mode 100644
index 00000000000..29b5d3facf3
--- /dev/null
+++ b/docs/strategies/timeout.md
@@ -0,0 +1,80 @@
+# Timeout resilience strategy
+
+## About
+
+- **Options**: [`TimeoutStrategyOptions`](../../src/Polly.Core/Timeout/TimeoutStrategyOptions.cs)
+- **Extensions**: `AddTimeout`
+- **Strategy Type**: Proactive
+- **Exceptions**:
+ - `TimeoutRejectedException`: Thrown when a delegate executed through a timeout strategy does not complete before the timeout.
+
+> [!NOTE]
+> Version 8 documentation for this strategy has not yet been migrated. For more information on timeout concepts and behavior, refer to the [older documentation](https://github.com/App-vNext/Polly/wiki/Timeout).
+
+## Usage
+
+
+```cs
+// Add timeout using the default options.
+// See https://github.com/App-vNext/Polly/blob/main/docs/strategies/timeout.md#defaults for default values.
+new ResiliencePipelineBuilder()
+ .AddTimeout(new TimeoutStrategyOptions());
+
+// To add a timeout with a custom TimeSpan duration
+new ResiliencePipelineBuilder()
+ .AddTimeout(TimeSpan.FromSeconds(3));
+
+// To add a timeout using a custom timeout generator function
+new ResiliencePipelineBuilder()
+ .AddTimeout(new TimeoutStrategyOptions
+ {
+ TimeoutGenerator = args =>
+ {
+ // Note: the timeout generator supports asynchronous operations
+ return new ValueTask(TimeSpan.FromSeconds(123));
+ }
+ });
+
+// To add a timeout and listen for timeout events
+new ResiliencePipelineBuilder()
+ .AddTimeout(new TimeoutStrategyOptions
+ {
+ TimeoutGenerator = args =>
+ {
+ // Note: the timeout generator supports asynchronous operations
+ return new ValueTask(TimeSpan.FromSeconds(123));
+ },
+ OnTimeout = args =>
+ {
+ Console.WriteLine($"{args.Context.OperationKey}: Execution timed out after {args.Timeout.TotalSeconds} seconds.");
+ return default;
+ }
+ });
+```
+
+
+Example execution:
+
+
+```cs
+var pipeline = new ResiliencePipelineBuilder()
+ .AddTimeout(TimeSpan.FromSeconds(3))
+ .Build();
+
+HttpResponseMessage httpResponse = await pipeline.ExecuteAsync(
+ async ct =>
+ {
+ // Execute a delegate that takes a CancellationToken as an input parameter.
+ return await httpClient.GetAsync(endpoint, ct);
+ },
+ cancellationToken);
+```
+
+
+## Defaults
+
+| Property | Default Value | Description |
+| ------------------ | ------------- | -------------------------------------------- |
+| `Timeout` | 30 seconds | The default timeout used by the strategy. |
+| `TimeoutGenerator` | `null` | Generates the timeout for a given execution. |
+| `OnTimeout` | `null` | Event that is raised when timeout occurs. |
diff --git a/src/Polly.RateLimiting/RateLimiterStrategyOptions.cs b/src/Polly.RateLimiting/RateLimiterStrategyOptions.cs
index f35c83c84dc..29ceb354de7 100644
--- a/src/Polly.RateLimiting/RateLimiterStrategyOptions.cs
+++ b/src/Polly.RateLimiting/RateLimiterStrategyOptions.cs
@@ -13,6 +13,15 @@ public class RateLimiterStrategyOptions : ResilienceStrategyOptions
///
public RateLimiterStrategyOptions() => Name = RateLimiterConstants.DefaultName;
+ ///
+ /// Gets or sets a rate limiter delegate that produces .
+ ///
+ ///
+ /// The default value is . If this property is , then the strategy
+ /// will use a created using .
+ ///
+ public Func>? RateLimiter { get; set; }
+
///
/// Gets or sets the default rate limiter options.
///
@@ -37,13 +46,4 @@ public class RateLimiterStrategyOptions : ResilienceStrategyOptions
/// The default value is .
///
public Func? OnRejected { get; set; }
-
- ///
- /// Gets or sets a rate limiter delegate that produces .
- ///
- ///
- /// The default value is . If this property is , then the strategy
- /// will use a created using .
- ///
- public Func>? RateLimiter { get; set; }
}
diff --git a/src/Snippets/Docs/CircuitBreaker.cs b/src/Snippets/Docs/CircuitBreaker.cs
index 2fb66df26e2..568d8bdafcc 100644
--- a/src/Snippets/Docs/CircuitBreaker.cs
+++ b/src/Snippets/Docs/CircuitBreaker.cs
@@ -13,6 +13,7 @@ public static async Task Usage()
#region circuit-breaker
// Add circuit breaker with default options.
+ // See https://github.com/App-vNext/Polly/blob/main/docs/strategies/circuit-breaker.md#defaults for default values.
new ResiliencePipelineBuilder().AddCircuitBreaker(new CircuitBreakerStrategyOptions());
// Add circuit breaker with customized options:
diff --git a/src/Snippets/Docs/Fallback.cs b/src/Snippets/Docs/Fallback.cs
index 3fc375f38b8..cf9a6706462 100644
--- a/src/Snippets/Docs/Fallback.cs
+++ b/src/Snippets/Docs/Fallback.cs
@@ -10,7 +10,7 @@ public static void Usage()
{
#region fallback
- // Use a fallback/substitute value if an operation fails.
+ // Add a fallback/substitute value if an operation fails.
new ResiliencePipelineBuilder()
.AddFallback(new FallbackStrategyOptions
{
diff --git a/src/Snippets/Docs/Hedging.cs b/src/Snippets/Docs/Hedging.cs
index 09e2723c1d2..8e1ae8e58dd 100644
--- a/src/Snippets/Docs/Hedging.cs
+++ b/src/Snippets/Docs/Hedging.cs
@@ -13,6 +13,7 @@ public static void Usage()
#region hedging
// Add hedging with default options.
+ // See https://github.com/App-vNext/Polly/blob/main/docs/strategies/hedging.md#defaults for default values.
new ResiliencePipelineBuilder()
.AddHedging(new HedgingStrategyOptions());
diff --git a/src/Snippets/Docs/RateLimiter.cs b/src/Snippets/Docs/RateLimiter.cs
index c46886007be..2ac2cfbe02f 100644
--- a/src/Snippets/Docs/RateLimiter.cs
+++ b/src/Snippets/Docs/RateLimiter.cs
@@ -11,6 +11,7 @@ public static void Usage()
#region rate-limiter
// Add rate limiter with default options.
+ // See https://github.com/App-vNext/Polly/blob/main/docs/strategies/rate-limiter.md#defaults for default values.
new ResiliencePipelineBuilder()
.AddRateLimiter(new RateLimiterStrategyOptions());
diff --git a/src/Snippets/Docs/Retry.cs b/src/Snippets/Docs/Retry.cs
index 9d1fca8ac0c..3973f8f4910 100644
--- a/src/Snippets/Docs/Retry.cs
+++ b/src/Snippets/Docs/Retry.cs
@@ -12,7 +12,8 @@ public static void Usage()
{
#region retry
- // Add retry using the default options
+ // Add retry using the default options.
+ // See https://github.com/App-vNext/Polly/blob/main/docs/strategies/retry.md#defaults for default values.
new ResiliencePipelineBuilder().AddRetry(new RetryStrategyOptions());
// For instant retries with no delay
diff --git a/src/Snippets/Docs/Timeout.cs b/src/Snippets/Docs/Timeout.cs
index 90b7270d83d..929ecd22faf 100644
--- a/src/Snippets/Docs/Timeout.cs
+++ b/src/Snippets/Docs/Timeout.cs
@@ -11,7 +11,8 @@ public static async Task Usage()
{
#region timeout
- // To add timeout using the default options
+ // Add timeout using the default options.
+ // See https://github.com/App-vNext/Polly/blob/main/docs/strategies/timeout.md#defaults for default values.
new ResiliencePipelineBuilder()
.AddTimeout(new TimeoutStrategyOptions());
diff --git a/test/Polly.Core.Tests/CircuitBreaker/Controller/ScheduledTaskExecutorTests.cs b/test/Polly.Core.Tests/CircuitBreaker/Controller/ScheduledTaskExecutorTests.cs
index 9dc91d9b94e..4b85dd4fc99 100644
--- a/test/Polly.Core.Tests/CircuitBreaker/Controller/ScheduledTaskExecutorTests.cs
+++ b/test/Polly.Core.Tests/CircuitBreaker/Controller/ScheduledTaskExecutorTests.cs
@@ -24,7 +24,7 @@ public async Task ScheduleTask_Success_EnsureExecuted()
}
[Fact]
- public async Task ScheduleTask_OperationCancelledException_EnsureExecuted()
+ public async Task ScheduleTask_OperationCanceledException_EnsureExecuted()
{
using var scheduler = new ScheduledTaskExecutor();
scheduler.ScheduleTask(