Rate Limiter
A production-ready, thread-safe rate limiter library for Go applications. Control the number of requests per key (user/IP/token) in a given time frame using the Token Bucket algorithm.
๐ฏ Problem Being Solved
In modern applications, you often need to:
- Prevent abuse by limiting API requests per user/IP
- Protect resources from being overwhelmed by too many requests
- Ensure fair usage across multiple clients
- Comply with rate limits when calling external APIs
This library provides a simple, efficient, and thread-safe solution for implementing rate limiting in your Go applications.
โจ Features
- ๐ Production-ready - Thread-safe with comprehensive test coverage
- ๐ฏ Simple API - Easy to integrate with just a few lines of code
- ๐ **Thrโฆ
Rate Limiter
A production-ready, thread-safe rate limiter library for Go applications. Control the number of requests per key (user/IP/token) in a given time frame using the Token Bucket algorithm.
๐ฏ Problem Being Solved
In modern applications, you often need to:
- Prevent abuse by limiting API requests per user/IP
- Protect resources from being overwhelmed by too many requests
- Ensure fair usage across multiple clients
- Comply with rate limits when calling external APIs
This library provides a simple, efficient, and thread-safe solution for implementing rate limiting in your Go applications.
โจ Features
- ๐ Production-ready - Thread-safe with comprehensive test coverage
- ๐ฏ Simple API - Easy to integrate with just a few lines of code
- ๐ Thread-safe - Uses
sync.RWMutexfor concurrent access - ๐พ In-memory storage - Fast, zero-dependency storage (Redis support planned)
- ๐ชฃ Token Bucket algorithm - Smooth rate limiting with burst support
- ๐ Detailed results - Get remaining tokens, reset time, and retry-after duration
- ๐งน Automatic cleanup - Optional cleanup of stale entries to prevent memory leaks
- ๐งช Well-tested - Extensive unit tests including concurrency tests
๐ฆ Installation
go get github.com/yasserelgammal/rate-limiter
๐ Quick Start
Basic Usage
package main
import (
"fmt"
"time"
"github.com/yasserelgammal/rate-limiter/limiter"
"github.com/yasserelgammal/rate-limiter/store"
)
func main() {
// Configure: 10 requests per second with burst of 20
config := limiter.Config{
Rate: 10,
Duration: time.Second,
Burst: 20,
}
// Create in-memory store
memStore := store.NewMemoryStore(5 * time.Minute)
defer memStore.Close()
// Create rate limiter
rateLimiter, err := limiter.NewTokenBucket(config, memStore)
if err != nil {
panic(err)
}
// Check if request is allowed
userID := "user123"
if rateLimiter.Allow(userID) {
fmt.Println("โ
Request allowed")
} else {
fmt.Println("โ Rate limit exceeded")
}
}
Advanced Usage with Detailed Results
// Get detailed rate limit information
result := rateLimiter.AllowN("user123", 1)
if result.Allowed {
fmt.Printf("โ
Request allowed. Remaining: %d\n", result.Remaining)
} else {
fmt.Printf("โ Rate limited. Retry after: %v\n", result.RetryAfter)
fmt.Printf(" Reset at: %v\n", result.ResetAt)
}
HTTP Middleware Example
func rateLimitMiddleware(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// Use IP address as rate limit key
clientIP := r.RemoteAddr
result := rateLimiter.AllowN(clientIP, 1)
// Set rate limit headers
w.Header().Set("X-RateLimit-Remaining", fmt.Sprintf("%d", result.Remaining))
w.Header().Set("X-RateLimit-Reset", result.ResetAt.Format(time.RFC3339))
if !result.Allowed {
w.Header().Set("Retry-After", fmt.Sprintf("%.0f", result.RetryAfter.Seconds()))
w.WriteHeader(http.StatusTooManyRequests)
json.NewEncoder(w).Encode(map[string]string{
"error": "Rate limit exceeded",
"retry_after": result.RetryAfter.String(),
})
return
}
next(w, r)
}
}
๐ API Reference
Configuration
type Config struct {
Rate int64 // Number of requests allowed per Duration
Duration time.Duration // Time window for the rate limit
Burst int64 // Maximum burst capacity
}
Example configurations:
Rate: 100, Duration: time.Minute, Burst: 100- 100 requests per minuteRate: 10, Duration: time.Second, Burst: 20- 10 req/s with burst of 20Rate: 1000, Duration: time.Hour, Burst: 1000- 1000 requests per hour
RateLimiter Interface
type RateLimiter interface {
// Allow checks if a single request should be allowed
Allow(key string) bool
// AllowN checks if n requests should be allowed
AllowN(key string, n int64) Result
// Reset clears rate limit for a specific key
Reset(key string)
// ResetAll clears all rate limits
ResetAll()
}
Result Structure
type Result struct {
Allowed bool // Whether the request is allowed
Remaining int64 // Tokens remaining in current window
ResetAt time.Time // When the rate limit resets
RetryAfter time.Duration // How long to wait before retrying (if denied)
}
๐๏ธ Project Structure
rate-limiter/
โโโ limiter/ # Core rate limiting logic
โ โโโ limiter.go # Interface and configuration
โ โโโ token_bucket.go # Token Bucket implementation
โ โโโ token_bucket_test.go # Comprehensive tests
โ โโโ errors.go # Error definitions
โ
โโโ store/ # Storage implementations
โ โโโ store.go # Storage interface
โ โโโ memory.go # Thread-safe in-memory store
โ โโโ memory_test.go # Store tests
โ
โโโ examples/ # Usage examples
โ โโโ basic/ # Basic usage example
โ โ โโโ main.go
โ โโโ http_server/ # HTTP server with middleware
โ โโโ templates/ # HTML templates
โ โ โโโ index.html
โ โโโ main.go
โ
โโโ go.mod # Go module definition
โโโ Makefile # Development tasks
โโโ README.md # Main documentation
โโโ LICENSE # MIT License
โโโ CONTRIBUTING.md # Contribution guidelines
โโโ .gitignore # Git ignore rules
๐งช Running Tests
# Run all tests
go test ./...
# Run tests with coverage
go test -cover ./...
# Run tests with race detection
go test -race ./...
# Run benchmarks
go test -bench=. ./...
Test Coverage
The library includes comprehensive tests covering:
- โ Basic allow/deny functionality
- โ Token refill behavior
- โ Multiple concurrent keys
- โ Thread-safety with race detection
- โ Edge cases and error handling
- โ Benchmark tests for performance
๐ฎ Running the Example
# Navigate to the example directory
cd examples/http_server
# Run the server
go run main.go
Then open your browser to http://localhost:8080 for an interactive demo, or use curl:
# Make a request
curl http://localhost:8080/api/data
# Check rate limit status
curl http://localhost:8080/api/status
# Test rate limiting
for i in {1..15}; do
curl -i http://localhost:8080/api/data
echo ""
done
๐ง Configuration Examples
Strict Rate Limiting (API Protection)
config := limiter.Config{
Rate: 100, // 100 requests
Duration: time.Minute, // per minute
Burst: 100, // no burst allowance
}
Lenient with Burst (User-facing API)
config := limiter.Config{
Rate: 10, // 10 requests
Duration: time.Second, // per second
Burst: 50, // allow bursts up to 50
}
Hourly Limit (Background Jobs)
config := limiter.Config{
Rate: 1000, // 1000 requests
Duration: time.Hour, // per hour
Burst: 1000, // full capacity available
}
๐ค Contributing
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
๐ License
This project is licensed under the MIT License - see the LICENSE file for details.
๐ Support & Contact
If you need help, have a question, or want to suggest an improvement:
๐ Issues: Report bugs or request features https://github.com/yasserelgammal/rate-limiter/issues
๐ฌ Discussions: Ask questions or share ideas https://github.com/yasserelgammal/rate-limiter/discussions
๐ผ LinkedIn: Connect with me https://www.linkedin.com/in/elgammal
Made with โค๏ธ by Yasser Elgammal
If you find this project useful, please consider giving it a โญ๏ธ on GitHub!