The purpose of this project is to simulate a real-world scalable rate-limiting mechanism in a distributed .NET backend. This is part of a larger backend engineering exercise plan focused on:
- High throughput systems
- Resilience engineering
- System design mastery
This is not a production-ready rate limiter. It’s an educational prototype.
- Granular control over requests per rolling window
- Avoids burstiness compared to fixed-window
- Lua script used inside Redis for atomic operations
- Centralized state tracking per user/IP
- Ensures consistency across multiple app instances
- A custom
RateLimitMiddlewareintercepts HTTP requests - Clean separation from business logic
- Redis operations are wrapped in:
- Timeout policy
- Retry with backoff
- Circuit breaker
- Resilience logic is extracted into
RedisPollyPolicy.cs
RateLimiter.SlidingWindowPractice
├── Core
│ ├── Interfaces/IRateLimiter.cs
│ └── Services/SlidingWindowRateLimiter.cs
│
├── Infrastructure
│ ├── Helpers/CacheKeyHelper.cs
│ ├── Storage
│ │ ├── Constants/CacheKeyConstants.cs
│ │ └── Redis
│ │ ├── RedisConnectionFactory.cs
│ │ ├── RedisRateLimitCacheStore.cs
│ │ ├── RedisScriptLoader.cs
│ │ ├── RedisScriptRegistry.cs
│ │ ├── Resilience/RedisPollyPolicy.cs
│ │ ├── Scripts/sliding_window.lua
│ │ ├── Interfaces/
│ │ └── Constants/
│ └── Web
│ ├── Middlewares/RateLimitMiddleware.cs
│ ├── Models/RequestContext.cs
│ ├── Options/ConnectionStringsOption.cs
│ └── Interfaces/IRequestContext.cs
│
├── Program.cs
├── Dockerfile
├── appsettings.json
- Every incoming HTTP request passes through the
RateLimitMiddleware. - The middleware uses
IRateLimiterto decide whether to allow or block the request. - The actual limiting logic is implemented via
SlidingWindowRateLimiter:- Generates Redis keys using
CacheKeyHelper - Executes a Lua script (
sliding_window.lua) in Redis to ensure atomicity
- Generates Redis keys using
- Redis interactions are made resilient with Polly (timeouts, retries, circuit breakers).
- If rate limit is exceeded →
429 Too Many Requests.