---
title: "How to implement like bucket rate limit?"  
description: "How to implement like bucket rate limit?"  
author: "Anubhav Sharma"  
published: 2026-01-14  
updated: 2026-01-18  
canonical: https://answers.mindstick.com/qa/116285/how-to-implement-like-bucket-rate-limit  
category: "application"  
tags: ["api"]  
reading_time: 4 minutes  

---

# How to implement like bucket rate limit?

## Answers

### Answer by Ravi Vishwakarma

A **token bucket rate limiter** is the most practical and production-friendly way to protect an API. Below is a **clean, real-world implementation guide**, starting from concept → ASP.NET API code → distributed ([Redis](https://www.mindstick.com/interview/34023/how-do-you-implement-caching-in-dot-net-e-g-memorycache-distributedcache-redis)) version → [best practices](https://www.mindstick.com/articles/337208/best-practices-for-structuring-html-forms).

I’ll focus on [**ASP.NET (MVC / Web API)**](https://www.mindstick.com/blog/369/introduction-to-the-asp-dot-net-web-api) since that’s what you usually work with.

## 1. Token Bucket – How It Works (Quick)

- Bucket has **capacity** (max tokens)
- Tokens refill at a **fixed rate**
- Each request consumes **1 token**
- If no token → **429 Too Many Requests**

Example:

```plaintext
Capacity = 100 tokens
Refill = 10 tokens / second
```

Allows:

- Short bursts
- Controlled average rate

## 2. In-Memory Token Bucket (Single Server)

### Step 1: Token Bucket Model

```cs
public class TokenBucket
{
    public int Capacity { get; }
    public double Tokens { get; private set; }
    public double RefillRate { get; } // tokens per second
    public DateTime LastRefill { get; private set; }

    private readonly object _lock = new object();

    public TokenBucket(int capacity, double refillRate)
    {
        Capacity = capacity;
        RefillRate = refillRate;
        Tokens = capacity;
        LastRefill = DateTime.UtcNow;
    }

    public bool TryConsume(int tokens = 1)
    {
        lock (_lock)
        {
            Refill();

            if (Tokens >= tokens)
            {
                Tokens -= tokens;
                return true;
            }

            return false;
        }
    }

    private void Refill()
    {
        var now = DateTime.UtcNow;
        var seconds = (now - LastRefill).TotalSeconds;

        if (seconds <= 0) return;

        Tokens = Math.Min(Capacity, Tokens + seconds * RefillRate);
        LastRefill = now;
    }
}
```

### Step 2: Rate Limit Store

```cs
public static class RateLimitStore
{
    private static readonly ConcurrentDictionary<string, TokenBucket> Buckets
        = new ConcurrentDictionary<string, TokenBucket>();

    public static TokenBucket GetBucket(string key)
    {
        return Buckets.GetOrAdd(key,
            _ => new TokenBucket(capacity: 100, refillRate: 10));
    }
}
```

### Step 3: API Filter (ASP.NET MVC / Web API)

```cs
public class TokenBucketRateLimitAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext context)
    {
        var request = context.HttpContext.Request;
        var key = request.UserHostAddress; // IP based

        var bucket = RateLimitStore.GetBucket(key);

        if (!bucket.TryConsume())
        {
            context.Result = new HttpStatusCodeResult(429, "Rate limit exceeded");
            return;
        }

        base.OnActionExecuting(context);
    }
}
```

### Step 4: Use It

```cs
[TokenBucketRateLimit]
public ActionResult GetUsers()
{
    return Json(data, JsonRequestBehavior.AllowGet);
}
```

## 3. Client Identification (Important)

You can rate-limit by:

| Type | Key |
| --- | --- |
| IP | `UserHostAddress` |
| API Key | `X-Api-Key` |
| User ID | JWT claim |
| Endpoint | `METHOD:/api/users` |

Example:

```plaintext
var key = $"{userId}:{request.HttpMethod}:{request.Path}";
```

## 4. Distributed Token Bucket (Redis – Production)

For **[multiple servers](https://www.mindstick.com/articles/334280/load-distribution-strategies-distributing-incoming-traffic-across-multiple-servers)**, memory won’t work.

### Redis Token Bucket (Atomic)

#### Redis Lua Script

```plaintext
local key = KEYS[1]
local capacity = tonumber(ARGV[1])
local refill_rate = tonumber(ARGV[2])
local now = tonumber(ARGV[3])

local bucket = redis.call("HMGET", key, "tokens", "timestamp")

local tokens = tonumber(bucket[1]) or capacity
local last = tonumber(bucket[2]) or now

local delta = math.max(0, now - last)
tokens = math.min(capacity, tokens + delta * refill_rate)

if tokens < 1 then
    redis.call("HMSET", key, "tokens", tokens, "timestamp", now)
    return 0
end

tokens = tokens - 1
redis.call("HMSET", key, "tokens", tokens, "timestamp", now)
redis.call("EXPIRE", key, 3600)

return 1
```

#### C# Redis Call (StackExchange.Redis)

```plaintext
var result = (int)redis.ScriptEvaluate(
    luaScript,
    new RedisKey[] { key },
    new RedisValue[]
    {
        capacity,
        refillRate,
        DateTimeOffset.UtcNow.ToUnixTimeSeconds()
    });

if (result == 0)
{
    return StatusCode(429);
}
```

## 5. Response Headers (Recommended)

Always tell clients their limit:

```plaintext
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 42
X-RateLimit-Reset: 1700000123
```

## 6. ASP.NET 7+ Built-in Alternative (FYI)

```plaintext
builder.Services.AddRateLimiter(options =>
{
    options.AddTokenBucketLimiter("api", opt =>
    {
        opt.TokenLimit = 100;
        opt.ReplenishmentPeriod = TimeSpan.FromSeconds(1);
        opt.TokensPerPeriod = 10;
    });
});
```

But since you’re **not on [ASP.NET Core](https://www.mindstick.com/articles/12946/get-started-with-asp-dot-net-core-mvc-and-visual-studio)**, the custom approach above is correct.

## 7. Which Algorithm Should You Use?

| Scenario | Best |
| --- | --- |
| Bursty traffic | Token Bucket |
| Strict per minute | Fixed Window |
| Smooth traffic | Leaky Bucket |
| Distributed | Token Bucket + Redis |

## 8. Common Mistakes

- Using `Thread.Sleep`
- No locking / atomicity
- No TTL cleanup
- Per-request DB hit
- [Rate limiting](https://answers.mindstick.com/qa/112126/how-do-i-implement-rate-limiting-to-prevent-abuse-of-apis) only by IP

## 9. Recommended Defaults

| Use Case | Capacity | Refill |
| --- | --- | --- |
| Public API | 100 | 10/sec |
| Auth API | 20 | 2/sec |
| Internal API | 1000 | 100/sec |

## 10. Want a Production-Ready Version?

I can:

- Convert this into **[HTTP module](https://www.mindstick.com/forum/34589/http-handler-vs-http-module) / middleware**
- Add **per-endpoint config**
- Add **Redis + fallback memory**
- Add **[sliding window](https://www.mindstick.com/forum/742/sql-keeping-count-of-occurrences-through-a-sliding-window) analytics**
- Add **admin override / whitelist**


---

Original Source: https://answers.mindstick.com/qa/116285/how-to-implement-like-bucket-rate-limit

Copyright © MindStick Software Pvt. Ltd. This Markdown version is provided for developers, AI systems, and offline reading.
