Skip to content

Rate Limiting

Per-client rate limiting middleware using a token bucket algorithm.

Package: github.com/oliverandrich/burrow/contrib/ratelimit

Depends on: none

Setup

srv := burrow.NewServer(
    ratelimit.New(),
    // ... other apps
)

With options:

ratelimit.New(
    ratelimit.WithKeyFunc(func(r *http.Request) string {
        // Custom key extraction (e.g., API key, user ID)
        return r.Header.Get("X-API-Key")
    }),
    ratelimit.WithOnLimited(func(w http.ResponseWriter, r *http.Request) {
        // Custom response for rate-limited requests
        http.Error(w, "Slow down!", http.StatusTooManyRequests)
    }),
)

How It Works

The rate limiter uses a token bucket algorithm from golang.org/x/time/rate:

  1. Each client (identified by IP or custom key) gets a bucket with burst tokens
  2. Tokens are refilled at rate tokens per second
  3. Each request consumes one token
  4. When the bucket is empty, the request is rejected with HTTP 429 and a Retry-After header

Idle client entries are automatically cleaned up at the configured interval.

Client Identification

By default, the client IP is extracted from RemoteAddr. When --ratelimit-trust-proxy is enabled, the middleware checks X-Forwarded-For and X-Real-IP headers first.

Override with WithKeyFunc() for custom identification (e.g., by API key or authenticated user).

Context Helpers

When a request is rate-limited, the Retry-After duration is available in the context:

import "github.com/oliverandrich/burrow/contrib/ratelimit"

retryAfter := ratelimit.RetryAfter(r.Context())

This is useful in custom OnLimited handlers.

Configuration

Flag Env Var Default Description
--ratelimit-rate RATELIMIT_RATE 10 Requests per second (token refill rate)
--ratelimit-burst RATELIMIT_BURST 20 Maximum burst size (bucket capacity)
--ratelimit-cleanup-interval RATELIMIT_CLEANUP_INTERVAL 1m Interval for sweeping expired entries
--ratelimit-trust-proxy RATELIMIT_TRUST_PROXY false Use X-Forwarded-For/X-Real-IP for client IP

Graceful Shutdown

The rate limiter implements HasShutdown to stop the background cleanup goroutine when the server shuts down.

Interfaces Implemented

Interface Description
burrow.App Required: Name(), Register()
Configurable Rate, burst, cleanup interval, and trust-proxy flags
HasMiddleware Rate limiting middleware
HasShutdown Stops the cleanup goroutine