Skip to content

Instantly share code, notes, and snippets.

@mohashari
Created March 14, 2026 15:12
Show Gist options
  • Select an option

  • Save mohashari/f0c0c3b38566b065ca18da12396ca870 to your computer and use it in GitHub Desktop.

Select an option

Save mohashari/f0c0c3b38566b065ca18da12396ca870 to your computer and use it in GitHub Desktop.
Code snippets — System Design Rate Limiting
func (rl *SlidingWindowLogLimiter) Allow(key string, userID string) bool {
now := time.Now().UnixMilli()
windowStart := now - rl.windowMs
pipe := redis.Pipeline()
// Remove old entries
pipe.ZRemRangeByScore(ctx, key, "0", strconv.FormatInt(windowStart, 10))
// Count current window
countCmd := pipe.ZCard(ctx, key)
// Add current request
pipe.ZAdd(ctx, key, redis.Z{Score: float64(now), Member: now})
pipe.Expire(ctx, key, time.Duration(rl.windowMs)*time.Millisecond)
pipe.Exec(ctx)
return countCmd.Val() < rl.limit
}
Current window count + Previous window count × (overlap ratio)
func (rl *SlidingWindowCounter) Allow(key string) bool {
now := time.Now()
currentWindow := now.Unix() / int64(rl.windowSec)
prevWindow := currentWindow - 1
currentKey := fmt.Sprintf("%s:%d", key, currentWindow)
prevKey := fmt.Sprintf("%s:%d", key, prevWindow)
pipe := redis.Pipeline()
currentCmd := pipe.Get(ctx, currentKey)
prevCmd := pipe.Get(ctx, prevKey)
pipe.Exec(ctx)
currentCount, _ := strconv.ParseFloat(currentCmd.Val(), 64)
prevCount, _ := strconv.ParseFloat(prevCmd.Val(), 64)
// How far into the current window are we? (0.0 to 1.0)
windowProgress := float64(now.Unix()%int64(rl.windowSec)) / float64(rl.windowSec)
// Weighted count
estimatedCount := currentCount + prevCount*(1-windowProgress)
if estimatedCount >= float64(rl.limit) {
return false
}
// Increment current window
redis.Incr(ctx, currentKey)
redis.Expire(ctx, currentKey, time.Duration(rl.windowSec*2)*time.Second)
return true
}
Rate: 10 tokens/second, Capacity: 100 tokens
- Quiet period → bucket fills to 100
- Burst → user can fire 100 requests instantly
- Steady state → 10 requests/second sustained
type TokenBucket struct {
rate float64 // tokens per second
capacity float64
tokens float64
lastTime time.Time
mu sync.Mutex
}
func (tb *TokenBucket) Allow() bool {
tb.mu.Lock()
defer tb.mu.Unlock()
now := time.Now()
elapsed := now.Sub(tb.lastTime).Seconds()
tb.lastTime = now
// Add tokens based on elapsed time
tb.tokens = math.Min(tb.capacity, tb.tokens+elapsed*tb.rate)
if tb.tokens >= 1 {
tb.tokens--
return true
}
return false
}
Incoming requests → [ Queue (max 100) ] → Process at fixed rate (10/s)
func RateLimitMiddleware(limiter Limiter) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Use IP + user ID as key (or just IP for unauthenticated)
key := getRateLimitKey(r)
result := limiter.Allow(key)
if !result.Allowed {
w.Header().Set("X-RateLimit-Limit", strconv.Itoa(result.Limit))
w.Header().Set("X-RateLimit-Remaining", "0")
w.Header().Set("X-RateLimit-Reset", strconv.FormatInt(result.ResetAt.Unix(), 10))
w.Header().Set("Retry-After", strconv.Itoa(int(result.RetryAfter.Seconds())))
http.Error(w, "Too Many Requests", http.StatusTooManyRequests)
return
}
w.Header().Set("X-RateLimit-Limit", strconv.Itoa(result.Limit))
w.Header().Set("X-RateLimit-Remaining", strconv.Itoa(result.Remaining))
next.ServeHTTP(w, r)
})
}
}
func getRateLimit(userTier string) (limit int, window time.Duration) {
switch userTier {
case "free":
return 100, time.Hour
case "pro":
return 1000, time.Hour
case "enterprise":
return 10000, time.Hour
default:
return 60, time.Hour // Unauthenticated
}
}
func (rl *FixedWindowLimiter) Allow(key string) bool {
now := time.Now()
windowKey := fmt.Sprintf("%s:%d", key, now.Unix()/60) // 1-minute windows
count, _ := redis.Incr(ctx, windowKey).Result()
if count == 1 {
redis.Expire(ctx, windowKey, 60*time.Second)
}
return count <= rl.limit
}
-- token_bucket.lua
local key = KEYS[1]
local rate = tonumber(ARGV[1])
local capacity = tonumber(ARGV[2])
local now = tonumber(ARGV[3])
local bucket = redis.call('HMGET', key, 'tokens', 'last_time')
local tokens = tonumber(bucket[1]) or capacity
local last_time = tonumber(bucket[2]) or now
local elapsed = now - last_time
tokens = math.min(capacity, tokens + elapsed * rate)
if tokens >= 1 then
tokens = tokens - 1
redis.call('HMSET', key, 'tokens', tokens, 'last_time', now)
redis.call('EXPIRE', key, 3600)
return 1
else
redis.call('HMSET', key, 'tokens', tokens, 'last_time', now)
return 0
end
Window: 0-59 seconds → 100 requests allowed
Window: 60-119 seconds → 100 requests allowed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment