Skip to main content

Overview

The rate limiter provides IP-based request throttling using token bucket algorithm. It automatically manages visitor lifecycles and cleans up inactive entries.

Types

IPRateLimiter

Manages rate limits for individual IP addresses with thread-safe operations.
main.go:29-35
type IPRateLimiter struct {
    ips map[string]*visitor
    mu  sync.Mutex
    r   rate.Limit
    b   int
}
ips
map[string]*visitor
Map of IP addresses to their visitor rate limiters
mu
sync.Mutex
Mutex for thread-safe access to the IP map
r
rate.Limit
Rate limit (requests per second)
b
int
Burst size (maximum requests allowed in a burst)

visitor

Internal type tracking individual IP rate limiters.
main.go:37-40
type visitor struct {
    limiter  *rate.Limiter
    lastSeen time.Time
}

Functions

NewIPRateLimiter()

Creates and initializes a new IPRateLimiter with specified rate limit and burst size.
main.go:56-64
func NewIPRateLimiter(r rate.Limit, b int) *IPRateLimiter {
    i := &IPRateLimiter{
        ips: make(map[string]*visitor),
        r:   r,
        b:   b,
    }
    go i.cleanupVisitors()
    return i
}
r
rate.Limit
required
Rate limit (requests per second). Use rate.Limit(n) to convert from int.
b
int
required
Burst size (maximum number of requests allowed in a burst)
return
*IPRateLimiter
Initialized rate limiter with background cleanup goroutine running

Usage Example

import "golang.org/x/time/rate"

// Allow 5 requests per second with burst of 10
limiter := NewIPRateLimiter(rate.Limit(5), 10)

GetLimiter()

Returns a rate limiter for the specified IP address, creating a new one if it doesn’t exist, and updates its last seen time.
main.go:68-81
func (i *IPRateLimiter) GetLimiter(ip string) *rate.Limiter {
    i.mu.Lock()
    defer i.mu.Unlock()

    v, exists := i.ips[ip]
    if !exists {
        limiter := rate.NewLimiter(i.r, i.b)
        i.ips[ip] = &visitor{limiter, time.Now()}
        return limiter
    }

    v.lastSeen = time.Now()
    return v.limiter
}
ip
string
required
IP address to get or create a limiter for
return
*rate.Limiter
Rate limiter instance for the specified IP

Usage Example

clientIP := "192.168.1.100"
if !limiter.GetLimiter(clientIP).Allow() {
    http.Error(w, "Too Many Requests", http.StatusTooManyRequests)
    return
}

cleanupVisitors()

Removes inactive visitors from the IP map based on a 3-minute inactivity duration. Runs continuously in a background goroutine.
main.go:84-95
func (i *IPRateLimiter) cleanupVisitors() {
    for {
        time.Sleep(time.Minute)
        i.mu.Lock()
        for ip, v := range i.ips {
            if time.Since(v.lastSeen) > 3*time.Minute {
                delete(i.ips, ip)
            }
        }
        i.mu.Unlock()
    }
}
This function is automatically started as a goroutine by NewIPRateLimiter(). It checks every minute and removes visitors inactive for more than 3 minutes.

Environment Variables

See Environment Variables for rate limiter configuration:
  • PROXY_RATE_LIMIT - Requests per second (default: 5)
  • PROXY_RATE_BURST - Burst size (default: 10)

Implementation Details

Cleanup Interval

The cleanup goroutine runs every 1 minute and removes visitors that haven’t been seen for more than 3 minutes.

Thread Safety

All operations use sync.Mutex to ensure thread-safe access to the internal IP map.

Token Bucket Algorithm

Uses Go’s golang.org/x/time/rate package which implements the token bucket algorithm for smooth rate limiting.

Build docs developers (and LLMs) love