Skip to content

Commit b2f771e

Browse files
author
Karl Solgård
committed
docs: Polly to readme
1 parent 293b4b5 commit b2f771e

1 file changed

Lines changed: 40 additions & 0 deletions

File tree

README.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,15 @@ Targets `net10.0`.
1313
| `ConcurrencyLimits` | Core algorithms and limiters. No transport dependencies. |
1414
| `ConcurrencyLimits.AspNetCore` | Request-pipeline middleware that returns 429 when the limit is reached. |
1515
| `ConcurrencyLimits.Grpc` | gRPC server and client interceptors (unary calls). |
16+
| `ConcurrencyLimits.Polly` | Polly v8 resilience strategy that gates executions through a limiter. |
1617

1718
## Install
1819

1920
```bash
2021
dotnet add package ConcurrencyLimits # core algorithms and limiters
2122
dotnet add package ConcurrencyLimits.AspNetCore # ASP.NET Core middleware
2223
dotnet add package ConcurrencyLimits.Grpc # gRPC interceptors
24+
dotnet add package ConcurrencyLimits.Polly # Polly v8 resilience strategy
2325
```
2426

2527
Or via `PackageReference`:
@@ -146,6 +148,44 @@ var clientInterceptor = new ConcurrencyLimitClientInterceptor(clientLimiter);
146148

147149
Only unary calls are limited (matching the Java implementation); streaming calls pass through. Rejected calls return `StatusCode.Unavailable`.
148150

151+
## Polly
152+
153+
Add an adaptive concurrency gate to any Polly v8 `ResiliencePipeline`. Acquire/release happens around the inner callback; successful runs feed RTT samples back into the limit algorithm.
154+
155+
```csharp
156+
using ConcurrencyLimits.Limit;
157+
using ConcurrencyLimits.Polly;
158+
using Polly;
159+
160+
ILimiter<ResilienceContext> limiter = new ResilienceContextLimiterBuilder()
161+
.WithLimit(Gradient2Limit.NewDefault())
162+
.PartitionByOperationKey()
163+
.AddPartition("checkout", 0.7)
164+
.AddPartition("search", 0.3)
165+
.Build();
166+
167+
ResiliencePipeline pipeline = new ResiliencePipelineBuilder()
168+
.AddConcurrencyLimit(limiter)
169+
.AddRetry(new() { MaxRetryAttempts = 2 })
170+
.Build();
171+
172+
var ctx = ResilienceContextPool.Shared.Get("checkout");
173+
try
174+
{
175+
var result = await pipeline.ExecuteAsync(static async c => await CallDownstreamAsync(c.CancellationToken), ctx);
176+
}
177+
catch (ConcurrencyLimitRejectedException)
178+
{
179+
// limiter shed the request — fall back / return 503 / etc.
180+
}
181+
finally
182+
{
183+
ResilienceContextPool.Shared.Return(ctx);
184+
}
185+
```
186+
187+
Customize the rejection exception via `ConcurrencyLimitStrategyOptions.RejectionExceptionFactory` (e.g. throw `BrokenCircuitException` so a downstream `Retry` or `Fallback` strategy reacts to it).
188+
149189
## Metrics
150190

151191
Limiters report through the `IMetricRegistry` abstraction. The default is `EmptyMetricRegistry`; implement `IMetricRegistry` to bridge to your metrics system (e.g. `System.Diagnostics.Metrics`).

0 commit comments

Comments
 (0)