Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/nimanikoo/Dotnet-RateLimiter/llms.txt

Use this file to discover all available pages before exploring further.

The ConcurrencyPolicy enforces a limit on the number of requests that are actively being processed at the same time, rather than on the number of requests arriving over a time period. A permit is acquired when a request enters the handler and released when the handler returns — regardless of how long that takes. This makes it the right tool for protecting resources that are sensitive to parallel load: databases, external HTTP services, expensive compute operations, and any endpoint that holds a shared resource lock.

How It Differs from Window-Based Limiting

Window-based policies (Fixed Window, Sliding Window, Token Bucket) answer the question: “How many requests has this caller made in the last N seconds?” The Concurrency limiter answers a different question: “How many requests are running right now?”
DimensionWindow-Based PoliciesConcurrency Policy
MeasuresRequests over a time periodSimultaneous in-flight requests
Permit lifecycleConsumed per requestHeld for the duration of the handler
Protects againstRequest-rate spikesParallel resource exhaustion
Appropriate forPublic APIs, quota enforcementDB-heavy endpoints, external calls

Registration

The policy is registered inside AddCustomRateLimiter in RateLimiterExtensions.cs:
options.AddConcurrencyLimiter("ConcurrencyPolicy", opt =>
{
    opt.PermitLimit = 7;
    opt.QueueLimit = 3;
    opt.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
}).RejectionStatusCode = 429;
OptionValueMeaning
PermitLimit7Maximum number of requests that can execute concurrently
QueueLimit3Maximum number of requests that can wait while all permits are held
QueueProcessingOrderOldestFirstThe request that has been waiting the longest is admitted first when a permit frees up
RejectionStatusCode429HTTP status returned when both the permit pool and queue are exhausted

Applying the Policy

Decorate any controller action with [EnableRateLimiting("ConcurrencyPolicy")]. From TestController.cs:
[HttpGet("concurrency"), EnableRateLimiting("ConcurrencyPolicy")]
public IEnumerable<WeatherForecast> TestConcurrency() =>
    Enumerable.Range(1, 5).Select(index => new WeatherForecast
        {
            Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
            TemperatureC = Random.Shared.Next(-20, 55),
            Summary = Summaries[Random.Shared.Next(Summaries.Length)]
        })
        .ToArray();

Queue Behavior

When all 7 permits are in use, incoming requests are not immediately rejected — they wait:
Requests 1–7   → Admitted immediately (holds a permit while executing)
Requests 8–10  → Queued (OldestFirst), waiting for a permit to be released
Request 11+    → Rejected with HTTP 429
As soon as any of the 7 active handlers complete and release their permit, the oldest waiting request in the queue is admitted. If all 3 queue slots are full and another request arrives, it is rejected with status 429 without waiting.

Use Cases

Endpoint TypeWhy Concurrency Limiting Helps
Database-heavy read/write operationsPrevents connection pool exhaustion under burst load
Outbound calls to external third-party APIsRespects upstream connection limits and avoids cascading failures
Expensive in-memory compute (e.g., PDF gen)Keeps CPU and memory usage within predictable bounds
Endpoints that hold distributed locksReduces lock contention and deadlock probability under high traffic
Combine with a timeout policy for best resilience. A request queued by the concurrency limiter will wait indefinitely for a permit unless you also enforce a request timeout. In ASP.NET Core, you can use app.UseRequestTimeouts() (available from .NET 8 onwards) alongside the concurrency limiter so that requests stuck in the queue for too long are cancelled gracefully rather than holding resources open. This two-layer approach — cap concurrency and cap wait time — gives you the strongest protection for expensive downstream calls.

Build docs developers (and LLMs) love