Skip to content

Instantly share code, notes, and snippets.

@hawaijar
Created August 1, 2025 09:33
Show Gist options
  • Save hawaijar/9c9e7ee2087821c6fdb7c5c672c287bc to your computer and use it in GitHub Desktop.
Save hawaijar/9c9e7ee2087821c6fdb7c5c672c287bc to your computer and use it in GitHub Desktop.
package main
import (
"fmt"
"log"
"time"
)
func main() {
// Example 1: Token Bucket (smooth rate limiting)
fmt.Println("=== Token Bucket Example ===")
// 10 tokens per second, burst capacity of 20
tokenBucket := ratelimiter.NewTokenBucket(10, 20)
userID := "user123"
// Burst: Use 15 tokens quickly
for i := 0; i < 15; i++ {
allowed, _ := tokenBucket.Allow(userID)
fmt.Printf("Request %d: %v\n", i+1, allowed)
}
// Wait for tokens to refill
fmt.Println("\nWaiting 2 seconds for tokens to refill...")
time.Sleep(2 * time.Second)
// Should have ~20 tokens now (refilled at 10/sec)
for i := 0; i < 5; i++ {
allowed, _ := tokenBucket.Allow(userID)
fmt.Printf("Request after wait %d: %v\n", i+1, allowed)
}
// Example 2: Sliding Window Log (precise but memory intensive)
fmt.Println("\n\n=== Sliding Window Log Example ===")
// 5 requests per 10 seconds
swLog := ratelimiter.NewSlidingWindowLog(5, 10*time.Second)
// Make 5 requests (should all pass)
for i := 0; i < 5; i++ {
allowed, _ := swLog.Allow("api-key-456")
fmt.Printf("Request %d: %v\n", i+1, allowed)
time.Sleep(1 * time.Second)
}
// 6th request should fail
allowed, _ := swLog.Allow("api-key-456")
fmt.Printf("Request 6 (should fail): %v\n", allowed)
// Wait for oldest request to expire
fmt.Println("\nWaiting 6 seconds for window to slide...")
time.Sleep(6 * time.Second)
// Should allow one more request now
allowed, _ = swLog.Allow("api-key-456")
fmt.Printf("Request after wait: %v\n", allowed)
// Example 3: Sliding Window Counter (balanced approach)
fmt.Println("\n\n=== Sliding Window Counter Example ===")
// 100 requests per minute, with 6 sub-windows (10-second buckets)
swCounter := ratelimiter.NewSlidingWindowCounter(100, time.Minute, 6)
// Simulate API traffic
fmt.Println("Simulating API traffic over 30 seconds...")
start := time.Now()
allowed := 0
rejected := 0
for time.Since(start) < 30*time.Second {
if ok, _ := swCounter.Allow("service-xyz"); ok {
allowed++
} else {
rejected++
}
time.Sleep(200 * time.Millisecond) // 5 requests per second
}
fmt.Printf("Results: %d allowed, %d rejected\n", allowed, rejected)
fmt.Printf("Effective rate: %.2f requests/minute\n", float64(allowed)*2)
// Example 4: Multiple users with different patterns
fmt.Println("\n\n=== Multi-User Example ===")
limiter := ratelimiter.NewTokenBucket(5, 10) // 5 req/sec, burst of 10
users := []string{"alice", "bob", "charlie"}
// Each user makes requests at different rates
for _, user := range users {
fmt.Printf("\nUser %s making requests:\n", user)
for i := 0; i < 8; i++ {
allowed, _ := limiter.Allow(user)
status := "✓ allowed"
if !allowed {
status = "✗ rejected"
}
fmt.Printf(" Request %d: %s\n", i+1, status)
// Different delays per user
if user == "alice" {
time.Sleep(100 * time.Millisecond) // Fast user
} else if user == "bob" {
time.Sleep(200 * time.Millisecond) // Medium user
} else {
time.Sleep(300 * time.Millisecond) // Slow user
}
}
}
// Example 5: Distributed rate limiting simulation
fmt.Println("\n\n=== Distributed System Example ===")
// Simulate 3 servers with shared rate limit
servers := []string{"server1", "server2", "server3"}
globalLimiter := ratelimiter.NewSlidingWindowLog(50, 10*time.Second)
// Each server processes requests for the same API key
apiKey := "shared-api-key"
requestCount := 0
for i := 0; i < 60; i++ {
server := servers[i%len(servers)]
if allowed, _ := globalLimiter.Allow(apiKey); allowed {
requestCount++
fmt.Printf("Request %d from %s: allowed (total: %d)\n",
i+1, server, requestCount)
} else {
fmt.Printf("Request %d from %s: RATE LIMITED\n", i+1, server)
}
time.Sleep(150 * time.Millisecond)
}
fmt.Printf("\nTotal allowed requests: %d/60 (limit was 50 per 10 seconds)\n",
requestCount)
}
// Helper function to demonstrate rate limiter with HTTP middleware
func RateLimitMiddleware(limiter ratelimiter.RateLimiter) func(handler func()) func() {
return func(handler func()) func() {
return func() {
// In real implementation, extract key from request (e.g., IP, API key)
key := "client-ip-192.168.1.1"
if allowed, _ := limiter.Allow(key); !allowed {
log.Println("Rate limit exceeded for", key)
// In real HTTP: return 429 Too Many Requests
return
}
// Process request
handler()
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment