ratelimit

package
v1.5.4 Latest Latest
Warning

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

Go to latest
Published: Jun 23, 2026 License: Apache-2.0 Imports: 11 Imported by: 0

Documentation

Overview

Package ratelimit provides token-bucket and sliding-window rate limiting middleware for Celeris.

New returns a celeris.HandlerFunc that enforces per-key request limits using a sharded token-bucket algorithm by default. Keys default to the client IP via celeris.Context.ClientIP; supply Config.KeyFunc to key on anything else (API key, user ID, etc.).

Core configuration fields: Config.RPS and Config.Burst set the static rate; Config.Rate accepts human-readable strings ("100-M", "1000-H") parsed by ParseRate. Config.RateFunc selects a per-request rate string, with distinct limiters cached up to Config.MaxDynamicLimiters (default 1024). Config.SlidingWindow switches to a sliding-window counter for smoother limiting near window boundaries. Config.Store plugs in an external backend (e.g. Redis) that implements Store; StoreUndo is the optional extension for token refunds used by Config.SkipFailedRequests and Config.SkipSuccessfulRequests.

On every allowed response the middleware sets X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers; denied responses (429) also receive Retry-After. Set Config.DisableHeaders to suppress all rate-limit headers. Config.ErrorHandler customises the 429 response (it supersedes the deprecated Config.LimitReached). The sentinel error ErrTooManyRequests is passed to ErrorHandler and is usable with errors.Is. ErrDynamicLimitersExhausted is returned when MaxDynamicLimiters is full.

ValidateConfig checks a Config for errors without panicking, useful when loading configuration from files or untrusted sources before calling New. New spawns background goroutines for bucket eviction; set Config.CleanupContext to a cancellable context to stop them when the middleware is no longer needed.

Documentation

Full guides and examples: https://goceleris.dev/docs/middleware-traffic

Index

Examples

Constants

This section is empty.

Variables

View Source
var ErrDynamicLimitersExhausted = errors.New("ratelimit: dynamic limiter map full")

ErrDynamicLimitersExhausted is returned when the dynamic limiter map has reached MaxDynamicLimiters and a new rate string is requested.

View Source
var ErrTooManyRequests = celeris.NewHTTPError(429, "Too Many Requests")

ErrTooManyRequests is returned when the rate limit is exceeded.

Functions

func New

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

New creates a rate limit middleware with the given config.

Example
package main

import (
	"github.com/goceleris/celeris/middleware/ratelimit"
)

func main() {
	// Zero-config: 10 RPS, burst 20, keyed by client IP.
	_ = ratelimit.New()
}
Example (ApiKey)
package main

import (
	"github.com/goceleris/celeris"

	"github.com/goceleris/celeris/middleware/ratelimit"
)

func main() {
	// Rate limit by API key header.
	_ = ratelimit.New(ratelimit.Config{
		Rate: "1000-H",
		KeyFunc: func(c *celeris.Context) string {
			return c.Header("x-api-key")
		},
	})
}
Example (HumanReadable)
package main

import (
	"github.com/goceleris/celeris/middleware/ratelimit"
)

func main() {
	// Human-readable rate: 100 requests per minute.
	_ = ratelimit.New(ratelimit.Config{
		Rate: "100-M",
	})
}

func ParseRate

func ParseRate(s string) (rps float64, burst int, err error)

ParseRate parses a human-readable rate string into RPS and burst values. Format: "<count>-<unit>" where unit is S (second), M (minute), H (hour), D (day). Examples: "100-M" (100 per minute), "1000-H" (1000 per hour), "5-S" (5 per second). The burst is set equal to the count.

Example
package main

import (
	"github.com/goceleris/celeris/middleware/ratelimit"
)

func main() {
	rps, burst, _ := ratelimit.ParseRate("100-M")
	_ = rps   // 1.6667 (100/60)
	_ = burst // 100
}

func ValidateConfig

func ValidateConfig(cfg Config) error

ValidateConfig checks the configuration for errors without panicking. Returns nil if the configuration is valid. Users loading config from files or untrusted sources can call this before New() to check their config safely.

Types

type Config

type Config struct {
	// Skip defines a function to skip this middleware for certain requests.
	Skip func(c *celeris.Context) bool

	// Store, when set, replaces the built-in sharded limiter with an
	// external storage backend (e.g., Redis). The store is responsible
	// for its own rate and burst logic; RPS, Burst, Shards, and
	// CleanupInterval are ignored.
	Store Store

	// RPS is the refill rate in requests per second per key. Default: 10.
	RPS float64

	// Burst is the maximum tokens (burst capacity). Default: 20.
	Burst int

	// Rate is a human-readable rate string (e.g., "100-M" for 100 per minute).
	// Supported units: S (second), M (minute), H (hour), D (day).
	// Takes precedence over RPS/Burst when set. If Burst is also set
	// explicitly, the user's Burst is preserved (Rate only overrides RPS).
	Rate string

	// RateFunc, when set, is called per-request to determine the rate.
	// Returns a rate string in the same format as Rate (e.g., "100-M").
	// Falls back to the static Rate/RPS/Burst when it returns an empty string.
	// Parsed via ParseRate.
	RateFunc func(c *celeris.Context) (rate string, err error)

	// KeyFunc extracts the rate limit key from the request. Default:
	// c.ClientIP() — which means the proxy middleware MUST be installed
	// (Server.Pre(proxy.New(...))) when running behind a reverse proxy.
	// Without proxy, ClientIP() returns the immediate peer (the load
	// balancer's address), so all real clients share one bucket and a
	// single noisy client triggers a global DoS for everyone behind the
	// same hop. With a misconfigured TrustedProxies range, attackers can
	// spoof X-Forwarded-For and escape their bucket. Verify the chain
	// before relying on the default.
	KeyFunc func(c *celeris.Context) string

	// SkipPaths lists paths to skip (exact match).
	SkipPaths []string

	// Shards is the number of lock shards. Default: runtime.NumCPU().
	// Rounded up to the next power of 2.
	Shards int

	// CleanupInterval is how often expired buckets are cleaned. Default: 1 minute.
	CleanupInterval time.Duration

	// CleanupContext, if set, controls cleanup goroutine lifetime.
	// When the context is cancelled, the cleanup goroutine stops.
	// If nil, cleanup runs until the process exits.
	CleanupContext context.Context

	// DisableHeaders disables X-RateLimit-* response headers.
	DisableHeaders bool

	// SlidingWindow, when true, uses a sliding window counter instead
	// of the default token bucket algorithm. The sliding window tracks
	// the previous and current window counts, weighted by the elapsed
	// fraction of the current window. This provides smoother rate limiting
	// near window boundaries.
	SlidingWindow bool

	// SkipFailedRequests, when true, refunds the token for requests
	// whose downstream handler returns a status >= 400. The token is
	// refunded after c.Next() completes.
	SkipFailedRequests bool

	// SkipSuccessfulRequests, when true, refunds the token for requests
	// whose downstream handler returns a status < 400. The token is
	// refunded after c.Next() completes.
	SkipSuccessfulRequests bool

	// LimitReached is called when a request is rate-limited.
	// If nil, returns 429 Too Many Requests.
	//
	// Deprecated: use [ErrorHandler] for naming consistency with the
	// rest of the middleware family (jwt, keyauth, basicauth, csrf,
	// recovery). LimitReached is kept working for backwards
	// compatibility; if both fields are set, ErrorHandler wins.
	LimitReached func(c *celeris.Context) error

	// ErrorHandler is called when a request is rate-limited. The err
	// argument is the sentinel [ErrTooManyRequests] so callers can
	// distinguish the cause from other middleware errors via
	// errors.Is. If nil, falls back to LimitReached, then to a
	// 429 Too Many Requests default.
	ErrorHandler func(c *celeris.Context, err error) error

	// MaxDynamicLimiters caps the number of distinct rate strings cached
	// when RateFunc is used. When exceeded, new rate strings are rejected
	// with an error. Default: 1024.
	MaxDynamicLimiters int
}

Config defines the rate limit middleware configuration.

type Store

type Store interface {
	// Allow checks if the request identified by key is allowed.
	// Returns whether the request is allowed, the remaining token count,
	// and the time at which the bucket resets.
	Allow(key string) (allowed bool, remaining int, resetAt time.Time, err error)
}

Store defines the interface for pluggable rate limit storage backends (e.g., Redis). The store handles its own rate/burst logic; Config.RPS and Config.Burst are ignored when Store is set.

type StoreUndo

type StoreUndo interface {
	Undo(key string) error
}

StoreUndo is an optional interface that Store implementations may satisfy to support token refunds. Used by SkipFailedRequests and SkipSuccessfulRequests.

Directories

Path Synopsis
Package memcachedstore provides a memcached-backed ratelimit.Store (token-bucket) built on the native celeris driver/memcached client.
Package memcachedstore provides a memcached-backed ratelimit.Store (token-bucket) built on the native celeris driver/memcached client.
Package redisstore provides a Redis-backed ratelimit.Store (token-bucket) built on the native celeris driver/redis client.
Package redisstore provides a Redis-backed ratelimit.Store (token-bucket) built on the native celeris driver/redis client.

Jump to

Keyboard shortcuts

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