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 BucketPolicy implements the classic token bucket algorithm, which gives callers a balance of tokens that they spend on requests and that are automatically refilled over time. Unlike window-based strategies that enforce a hard request count per interval, the token bucket explicitly permits short bursts — as long as the bucket has tokens available — while still enforcing a sustainable average rate through periodic replenishment.

How It Works

Imagine a bucket that holds up to TokenLimit tokens. Each request consumes one token. When the bucket is empty, requests either wait in a queue or are rejected. On a fixed replenishment schedule (ReplenishmentPeriod), TokensPerPeriod tokens are added back — up to the maximum TokenLimit.
Bucket capacity: 5 tokens
Initial state:   [●][●][●][●][●]  (full)

Request 1:       [●][●][●][●][ ]  → 200 OK
Request 2:       [●][●][●][ ][ ]  → 200 OK
Request 3:       [●][●][ ][ ][ ]  → 200 OK
Request 4:       [●][ ][ ][ ][ ]  → 200 OK
Request 5:       [ ][ ][ ][ ][ ]  → 200 OK
Request 6:       bucket empty → queue or 429

--- after 5 seconds (ReplenishmentPeriod) ---

Replenished:     [●][●][●][ ][ ]  (+3 TokensPerPeriod)
This model is well-suited to bursty callers: a user who has been idle for one replenishment period will have accumulated tokens and can send several requests in quick succession — exactly the pattern seen in interactive clients (e.g., search-as-you-type, file downloads).

Registration

The policy is registered inside AddCustomRateLimiter in RateLimiterExtensions.cs:
options.AddTokenBucketLimiter("BucketPolicy", opt =>
{
    opt.TokenLimit = 5;
    opt.QueueLimit = 2;
    opt.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
    opt.ReplenishmentPeriod = TimeSpan.FromSeconds(5);
    opt.AutoReplenishment = true;
    opt.TokensPerPeriod = 3;
}).RejectionStatusCode = 429;
OptionValueMeaning
TokenLimit5Maximum number of tokens the bucket can hold at any time
QueueLimit2Maximum requests that can wait when the bucket is empty
QueueProcessingOrderOldestFirstOldest waiting requests receive replenished tokens first
ReplenishmentPeriod5 secondsHow frequently tokens are added back to the bucket
AutoReplenishmenttrueThe runtime automatically triggers replenishment on the timer
TokensPerPeriod3Number of tokens added at each replenishment (capped at TokenLimit)
RejectionStatusCode429HTTP status returned when the bucket is empty and the queue is full

Applying the Policy

Decorate any controller action with [EnableRateLimiting("BucketPolicy")]. From TestController.cs:
[HttpGet("bucket"), EnableRateLimiting("BucketPolicy")]
public IEnumerable<WeatherForecast> TestBucket() =>
    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();

Effective Rate

With the above configuration, the sustained throughput is:
3 tokens replenished every 5 seconds = 0.6 requests/second average
However, a caller with a full bucket can burst up to 5 requests instantly before the sustained rate kicks in. The queue allows an additional 2 requests to wait rather than be immediately rejected.

When to Use

ScenarioRecommendation
Mobile or browser clients with search-as-you-type✅ BucketPolicy handles bursts well
File download or streaming endpoints with periodic access✅ Burst capacity absorbed naturally
APIs where a steady, predictable request rate is requiredConsider SlidingWindowPolicy
Multi-instance / distributed deploymentsUse Redis Fixed Window instead
AutoReplenishment = true means the ASP.NET Core rate limiter infrastructure automatically fires a background timer every ReplenishmentPeriod to add TokensPerPeriod tokens back to the bucket. You do not need to implement or register a separate hosted service or background worker — replenishment is fully managed by the runtime as long as the application is running.

Build docs developers (and LLMs) love