A lightweight, in-memory per-client sliding window rate limiter written in C#. Ships as a console application with three built-in demos that showcase concurrency safety, time-based window boundaries, and multi-client isolation.
- Sliding Window Log algorithm for precise per-request timestamp tracking
- Per-client rate limiting with isolated state and independent quotas
- Fine-grained locking that only contends within the same client
- TimeProvider abstraction enabling deterministic testing without real clock delays
- Thread-safe by design using ConcurrentDictionary and per-client locks
- Zero NuGet dependencies in the core rate limiter logic
- .NET 10 SDK or later
git clone https://github.com/your-username/TinyRateLimiter.git
cd TinyRateLimiter
dotnet run --project TinyRateLimiterTinyRateLimiter/
├── TinyRateLimiter.slnx
├── LICENSE.txt
└── TinyRateLimiter/
├── IRateLimiter.cs # Rate limiter contract
├── ClientState.cs # Per-client state (lock + timestamp queue)
├── SlidingWindowRateLimiter.cs # Core sliding window implementation
├── Program.cs # Entry point with three demos
└── TinyRateLimiter.csproj
The rate limiter uses the Sliding Window Log algorithm. Each client gets a queue of request timestamps. When a new request arrives:
- The system computes the window boundary by subtracting the configured duration from the current time.
- Expired timestamps older than the window boundary are evicted from the front of the queue.
- If the remaining count is at or above the limit, the request is rejected.
- Otherwise, the current timestamp is enqueued and the request is allowed.
All of this happens under a per-client lock, so different clients never block each other.
using TinyRateLimiter;
var limiter = new SlidingWindowRateLimiter(
limit: 5,
window: TimeSpan.FromSeconds(10));
if (limiter.AllowRequest("user-123"))
{
// Process the request
}
else
{
// Rate limit exceeded
}For deterministic testing, inject a FakeTimeProvider:
using Microsoft.Extensions.Time.Testing;
var fakeTime = new FakeTimeProvider();
var limiter = new SlidingWindowRateLimiter(
limit: 5,
window: TimeSpan.FromSeconds(10),
timeProvider: fakeTime);
// Use limiter, then advance the clock
fakeTime.Advance(TimeSpan.FromSeconds(11));Demo 1 - Concurrency: Fires 100 parallel tasks against a single client with a limit of 5. Validates that exactly 5 are allowed and 95 are rejected under concurrent load.
Demo 2 - Sliding Window Boundaries: Uses a FakeTimeProvider to advance the clock in controlled steps, proving that capacity only resets after the full window has elapsed.
Demo 3 - Multi-Client Isolation: Sends requests from two different clients to confirm that one client reaching its limit does not affect the other.
This project is licensed under the MIT License.