slidingwindow

package
v0.0.26 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 24, 2026 License: MIT Imports: 6 Imported by: 0

README

slidingwindow middleware

Provides per-key sliding-window rate limiting with an optional burst allowance.

app.Use(slidingwindow.New(slidingwindow.Config{
    Rate: 100,
    Burst: 20,
    Window: time.Minute,
    MaxKeys: 65_536,
    KeyFunc: slidingwindow.ByIP,
    Store: kv.NewMemoryStore(),
}))

Use a shared bounded store for cross-replica enforcement. Normalize trusted proxy identity before choosing IP as the key.

Documentation

Overview

Package slidingwindow provides a sliding window rate limiter middleware. Unlike fixed-window limiters, sliding window accurately tracks request rates across window boundaries, preventing burst spikes at window edges.

The algorithm uses a logarithmic counter approach: - Each request increments a counter with a timestamp - Old requests are expired based on the window size - The rate is calculated as requests-per-second over the window

Features: - Per-IP, per-key, or global rate limiting - Burst allowance for short traffic spikes - Retry-After header support - Custom key extraction (by IP, header, route, etc.) - Clean headers: X-RateLimit-*, Retry-After

Index

Constants

This section is empty.

Variables

View Source
var DefaultConfig = Config{
	Rate:            100,
	Burst:           100,
	Window:          time.Second,
	MaxKeys:         65536,
	CleanupInterval: time.Minute,
	Message:         "Rate limit exceeded",
	StatusCode:      429,
}

DefaultConfig returns the default configuration.

Functions

func Allow

func Allow(store kv.Store, key string, rate, burst int, windowSize time.Duration) (allowed bool, remaining int, retryAfter time.Duration, err error)

allowViaStore implements Store.Allow on top of any kv.Store, shared by MemoryStore and FileStore. It reproduces the exact admission algorithm this package has always used (expire timestamps outside the window, compute remaining against rate, allow bursts up to rate+burst, otherwise reject with a retry-after derived from the oldest in-window timestamp); only the representation changes, from an in-memory compacting ring buffer (an optimization to avoid reallocating the timestamp slice on every request) to a plain trimmed slice that round-trips through JSON on every Mutate call, since kv.Store already reallocates on every write and the ring buffer's head/count bookkeeping has nothing left to optimize once that's true.

func ByComposite

func ByComposite(fns ...func(fh.Ctx) string) func(fh.Ctx) string

ByComposite combines multiple key functions.

func ByHeader

func ByHeader(name string) func(fh.Ctx) string

ByHeader extracts a header value as the rate limit key.

func ByIP

func ByIP(ctx fh.Ctx) string

ByIP extracts the client IP as the rate limit key.

func ByRoute

func ByRoute(ctx fh.Ctx) string

ByRoute extracts the route path as the rate limit key (global per-route limit).

func New

func New(config ...Config) fh.HandlerFunc

New creates a sliding window rate limiter middleware.

Types

type Config

type Config struct {
	// Rate is the maximum requests per window. Default: 100.
	Rate int

	// Burst is the maximum burst size above the rate. Default: same as Rate.
	Burst int

	// Window is the sliding window duration. Default: 1 second.
	Window time.Duration

	// KeyFunc extracts the rate limit key from the request.
	// Default: client IP address.
	KeyFunc func(ctx fh.Ctx) string

	// MaxKeys is the maximum number of tracked keys. Default: 65536.
	MaxKeys int

	// CleanupInterval is how often to clean expired keys. Default: 1 minute.
	CleanupInterval time.Duration

	// Message is the error message for rate-limited requests.
	Message string

	// StatusCode is the HTTP status for rate-limited requests. Default: 429.
	StatusCode int

	// Next is an optional skip function.
	Next func(ctx fh.Ctx) bool

	// OnLimitReached is called when a request is rate-limited.
	OnLimitReached func(ctx fh.Ctx, key string, remaining int)

	// Store holds per-key sliding window state. Defaults to a new kv.MemoryStore.
	// Pass any kv.Store implementation, such as kv.NewFileStore, when creating
	// the middleware.
	Store kv.Store
}

Config holds configuration for the sliding window rate limiter.

type Limiter

type Limiter struct {
	// contains filtered or unexported fields
}

func NewLimiter

func NewLimiter(config ...Config) *Limiter

NewLimiter creates a new sliding window rate limiter.

func (*Limiter) Allow

func (l *Limiter) Allow(key string) (bool, int, time.Duration)

Allow checks if a request with the given key is allowed. Returns (allowed, remaining, retryAfter).

func (*Limiter) Len

func (l *Limiter) Len() (int, error)

Len reports the number of distinct keys currently tracked. It is a thin pass-through to the underlying kv.MemoryStore, exposed so callers (and this package's own tests) can observe the MaxKeys cardinality bound without reaching into unexported fields.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL