A production-grade, high-performance rate limiting library for Go applications with support for multiple backends and advanced features.
- Multiple Backends: In-memory and Redis backends with consistent API
- Token Bucket Algorithm: Efficient rate limiting with configurable refill rates
- Context Support: Full context cancellation and timeout support
- Production Ready: Comprehensive error handling, health checks, and monitoring
- Thread Safe: Concurrent access with proper locking mechanisms
- Configurable: Flexible configuration with sensible defaults
- Comprehensive Testing: Extensive test coverage with benchmarks
- Clean API: Simple, intuitive interface for common use cases
go get github.com/devrob-go/go-rate-limiterpackage main
import (
"context"
"fmt"
"time"
"github.com/devrob-go/go-rate-limiter/pkg/limiter"
"github.com/devrob-go/go-rate-limiter/pkg/backend"
"github.com/devrob-go/go-rate-limiter/pkg/config"
)
func main() {
// Create configuration
cfg := config.DefaultConfig()
// Create in-memory backend
backend, err := backend.NewInMemoryBackend(backend.DefaultOptions())
if err != nil {
panic(err)
}
// Create rate limiter
limiter, err := limiter.New(backend, cfg)
if err != nil {
panic(err)
}
defer limiter.Close(context.Background())
// Use rate limiter
ctx := context.Background()
allowed, err := limiter.Take(ctx, "user_123", 1)
if err != nil {
panic(err)
}
if allowed {
fmt.Println("Request allowed")
} else {
fmt.Println("Rate limit exceeded")
}
}package main
import (
"context"
"fmt"
"github.com/devrob-go/go-rate-limiter/pkg/limiter"
"github.com/devrob-go/go-rate-limiter/pkg/backend"
"github.com/devrob-go/go-rate-limiter/pkg/config"
)
func main() {
// Create configuration
cfg := config.DefaultConfig()
// Create Redis backend
backend, err := backend.NewRedisBackend("redis://localhost:6379", backend.DefaultOptions())
if err != nil {
panic(err)
}
// Create rate limiter
limiter, err := limiter.New(backend, cfg)
if err != nil {
panic(err)
}
defer limiter.Close(context.Background())
// Use rate limiter
ctx := context.Background()
allowed, err := limiter.Take(ctx, "user_123", 1)
if err != nil {
panic(err)
}
if allowed {
fmt.Println("Request allowed")
} else {
fmt.Println("Rate limit exceeded")
}
}// Set custom limits for specific keys
err := limiter.TakeWithLimit(ctx, "premium_user", 1, 1000, time.Minute)
if err != nil {
panic(err)
}
// Check if request would be allowed without consuming tokens
allowed, err := limiter.IsAllowed(ctx, "user_123", 1)
if err != nil {
panic(err)
}
if allowed {
fmt.Println("Request would be allowed")
}// Wait until tokens become available
err := limiter.Wait(ctx, "user_123", 1)
if err != nil {
if err == context.DeadlineExceeded {
fmt.Println("Timeout waiting for tokens")
} else {
panic(err)
}
}
fmt.Println("Tokens available")// Get current token bucket state
info, err := limiter.GetInfo(ctx, "user_123")
if err != nil {
panic(err)
}
fmt.Printf("Tokens: %d/%d, Next refill: %s\n",
info.Tokens, info.MaxTokens, info.NextRefill.Format(time.RFC3339))cfg := config.DefaultConfig()
// Default: 100 tokens, 1 second refill, 10 burst, 5 minute cleanupcfg := config.DefaultConfig().
WithDefaults(50, 2*time.Second, 5).
WithRedis("redis://localhost:6379").
WithInMemory(10*time.Minute, 5000)| Option | Description | Default |
|---|---|---|
DefaultLimit |
Maximum tokens per bucket | 100 |
DefaultRefill |
Token refill rate | 1 second |
DefaultBurst |
Burst allowance | 10 |
MaxKeys |
Maximum number of keys | 10,000 |
CleanupInterval |
Cleanup frequency | 5 minutes |
EnableMetrics |
Enable metrics collection | true |
EnableLogging |
Enable structured logging | true |
options := backend.DefaultOptions().
WithLimit(200).
WithRefill(500*time.Millisecond).
WithBurst(20)
backend, err := backend.NewInMemoryBackend(options)options := backend.DefaultOptions().
WithLimit(200).
WithRefill(500*time.Millisecond).
WithBurst(20)
backend, err := backend.NewRedisBackend("redis://localhost:6379", options)The library provides comprehensive error handling with custom error types:
import "github.com/devrob-go/go-rate-limiter/pkg/errors"
// Check error types
if errors.IsRateLimitExceeded(err) {
// Handle rate limit exceeded
}
if errors.IsValidationError(err) {
// Handle validation error
}
if errors.IsBackendError(err) {
// Handle backend error
}
if errors.IsTimeoutError(err) {
// Handle timeout error
}// Check backend health
err := limiter.HealthCheck(ctx)
if err != nil {
log.Printf("Health check failed: %v", err)
}
// Check limiter health
err = limiter.HealthCheck(ctx)
if err != nil {
log.Printf("Limiter health check failed: %v", err)
}// Gracefully shutdown the rate limiter
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
err := limiter.Close(ctx)
if err != nil {
log.Printf("Error during shutdown: %v", err)
}go test ./...go test -bench=. ./...go test -cover ./...The library is designed for high performance:
- In-Memory Backend: Sub-millisecond response times
- Redis Backend: Optimized with Lua scripts for atomic operations
- Concurrent Access: Thread-safe with minimal locking overhead
- Memory Efficient: Automatic cleanup of expired buckets
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ RateLimiter │ │ Backend │ │ Storage │
│ │───▶│ Interface │───▶│ (Memory/ │
│ - Validation │ │ │ │ Redis) │
│ - Context │ │ - Take() │ │ │
│ - Thread Safety │ │ - Reset() │ │ │
│ - Error Handling│ │ - GetInfo() │ │ │
└─────────────────┘ │ - SetLimit() │ └─────────────────┘
│ - Close() │
│ - HealthCheck() │
└─────────────────┘
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Ensure all tests pass
- Submit a pull request
This project is licensed under the MIT License - see the LICENSE file for details.
- Token bucket algorithm implementation
- Redis Lua script optimization
- Comprehensive error handling patterns
- Production-ready testing strategies