Build Status:
Code Coverage Report:
This is an implementation of a distributed rate limiter using the Token Bucket algorithm, backed by Redis, and built in Go. It's designed to be efficient, scalable, and production-ready.
Other algorithms are also implemented and can be selected using the RATE_LIMIT_STRATEGY variable in the .env -
- Leaky Bucket
- Fixed Window
- Sliding Window Log
- Moving Window Counter (Hybrid Sliding Window)
- Token Bucket algorithm using Redis atomic operations
- Clean architecture using Go interfaces and patterns
- Middleware-friendly HTTP integration
- Flexible configuration with Functional Options pattern
- Singleton limiter instance for safe shared use
- Works out-of-the-box with any Redis instance
- Unit tests using
stretchr/testify - Code coverage tracking via Codecov
| Pattern | Purpose |
|---|---|
| Strategy Pattern | Abstracts different rate limiting algorithms |
| Adapter Pattern | Encapsulates Redis operations through a Store interface |
| Functional Options | Clean and extensible configuration of the limiter |
| Singleton | Ensures only one limiter instance exists across the app |
| Middleware | Integrates rate limiting logic into HTTP stack cleanly |
- Go 1.20+
- Redis 6+
- go-redis client
- Testify for unit testing
- Codecov for real-time test coverage
.
├── main.go → Entrypoint for HTTP server
├── limiter/
│ ├── limiter.go → Limiter struct & functional options
│ ├── strategy.go → TokenBucket + RateLimiter interface
│ ├── store.go → RedisStore + Store interface
│ └── limiter_test.go → Unit tests for limiter
├── middleware/
│ └── ratelimit.go → HTTP middleware
└── .github/workflows/ci.yml → GitHub Actions CI pipeline
└── Taskfile.yml → Task runner for linting and testing
- Rate: 2 requests/sec
- Burst: 2 requests
- Keyed by a hardcoded client ID (can be extended to IP/user ID)
Redis stores count keys like rate:limiter:test-client and uses INCR and EXPIRE to count and auto-reset.
(I wasnt using Docker for Redis)
brew install redis
brew services start redistask run # using Taskfile.yaml(can use a script if you want, I kept the window short to be able to trigger it manually):
curl localhost:8080 # spam
redis-cli FLUSHALL # clearing Redis
curl localhost:6379 # checking Make more than 2 requests per second to get 429 Too Many Requests.
task lint # static analysistask test # unit tests with coveragetask coverage # HTML coverage reportRequest allowed: 2025-04-01T18:26:15+05:30
Request allowed: 2025-04-01T18:26:16+05:30
Rate limit exceeded
task: [run] go run main.go
Server running on :8080
New TTL set: 1s
Key: rate:limiter:test-client, Count: 1
New TTL set: 1s
Key: rate:limiter:test-client, Count: 1
Key: rate:limiter:test-client, Count: 2
Key: rate:limiter:test-client, Count: 3
Key: rate:limiter:test-client, Count: 4
Key: rate:limiter:test-client, Count: 5
New TTL set: 1s
Key: rate:limiter:test-client, Count: 1
Key: rate:limiter:test-client, Count: 2
- Sliding window or Leaky bucket algorithms
- Per-IP or API-key based throttling
- Admin dashboard for live metrics
- Redis Cluster or Sentinel support
- Prometheus metrics + Grafana dashboard
Crafted with care by me – designed to be readable and extensible. Will probably build on top of it later