ratelimit

package
v0.0.2 Latest Latest
Warning

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

Go to latest
Published: Sep 21, 2026 License: MIT Imports: 7 Imported by: 0

Documentation

Overview

Package ratelimit provides local rate-limiting primitives: a token bucket, a leaky bucket, and a concurrency limiter. They are transport-agnostic and can be composed into middleware or applied directly.

Index

Constants

View Source
const (
	// Unknown indicates the outcome could not be determined (store error).
	Unknown = iota
	// Allowed means the request is within quota and quota is not yet full.
	Allowed
	// HitQuota means the request is within quota and just filled it.
	HitQuota
	// OverQuota means the request exceeds the quota.
	OverQuota
)

PeriodLimit result codes. Unlike a boolean limiter, these let callers distinguish "allowed", "allowed but just hit the quota", and "rejected".

Variables

This section is empty.

Functions

This section is empty.

Types

type ConcurrencyLimiter

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

ConcurrencyLimiter limits the number of concurrently active operations. Unlike TokenBucket/LeakyBucket it is not time-based: the caller must explicitly release an acquired slot.

func NewConcurrencyLimiter

func NewConcurrencyLimiter(n int) *ConcurrencyLimiter

NewConcurrencyLimiter returns a ConcurrencyLimiter allowing n concurrent operations.

func (*ConcurrencyLimiter) Acquire

func (l *ConcurrencyLimiter) Acquire() bool

Acquire attempts to take a slot without blocking. It returns false when the concurrency limit is reached.

func (*ConcurrencyLimiter) Release

func (l *ConcurrencyLimiter) Release()

Release returns a previously acquired slot.

type LeakyBucket

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

LeakyBucket is a leaky-bucket rate limiter: requests fill a bucket of fixed capacity that leaks one request per interval.

func NewLeakyBucket

func NewLeakyBucket(capacity int, interval time.Duration) *LeakyBucket

NewLeakyBucket returns a LeakyBucket that holds up to capacity requests and leaks one request per interval.

func (*LeakyBucket) Allow

func (b *LeakyBucket) Allow() bool

Allow implements Limiter.

type Limiter

type Limiter interface {
	// Allow reports whether a single request may proceed.
	Allow() bool
}

Limiter decides whether a request may proceed.

type PeriodLimit

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

PeriodLimit limits how many requests are allowed within a rolling (or aligned) time window, backed by a shared Store for cross-instance coordination.

func NewPeriodLimit

func NewPeriodLimit(period time.Duration, quota int, store Store, keyPrefix string,
	opts ...PeriodOption) *PeriodLimit

NewPeriodLimit returns a PeriodLimit allowing quota requests per period, keyed under keyPrefix.

func (*PeriodLimit) Take

func (l *PeriodLimit) Take(key string) (int, error)

Take records one request for key and reports its result code.

func (*PeriodLimit) TakeCtx

func (l *PeriodLimit) TakeCtx(ctx context.Context, key string) (int, error)

TakeCtx is Take with a context.

type PeriodOption

type PeriodOption func(*PeriodLimit)

PeriodOption customizes a PeriodLimit.

func Align

func Align() PeriodOption

Align aligns the window to natural boundaries (e.g. a 1-day period resets at midnight rather than one day after first use).

type RateLimiter

type RateLimiter interface {
	// Acquire reports whether a request may proceed, consuming a token if so.
	Acquire(ctx context.Context) bool
	// Status reports the current (max, cur, interval) limiter state.
	Status(ctx context.Context) (max, cur int, interval time.Duration)
}

RateLimiter is a lightweight, local (non-distributed) rate limiter for non-critical paths where a Redis round-trip would be too heavy.

func NewQPSLimiter

func NewQPSLimiter(interval time.Duration, limit int) RateLimiter

NewQPSLimiter returns a local QPS limiter that refills to limit tokens every interval. The returned RateLimiter owns a background goroutine released when the limiter is garbage collected via the finalizer-free Stop-free design: callers using it for the process lifetime need no explicit shutdown.

func NewQPSLimiterWithStop

func NewQPSLimiterWithStop(interval time.Duration, limit int) (RateLimiter, func())

NewQPSLimiterWithStop returns a QPS limiter together with a stop function that releases its background goroutine.

type Store

type Store interface {
	// TakeTokens atomically consumes n tokens from the bucket identified by key,
	// which refills at rate tokens per second up to burst capacity. It reports
	// whether the tokens were granted.
	TakeTokens(ctx context.Context, key string, rate, burst, n int) (bool, error)
	// IncrWindow atomically increments the counter identified by key and returns
	// the new value. The first increment starts an expiry of window.
	IncrWindow(ctx context.Context, key string, window time.Duration) (int64, error)
	// Ping checks the health of the backing store.
	Ping(ctx context.Context) error
	// Close releases resources held by the store.
	Close() error
}

Store is the storage abstraction for distributed rate limiting. Implementations provide atomic operations across instances; a memory implementation is used for single-instance or testing, and a Redis implementation for multi-instance coordination. It is defined consumer-side (interface segregation) so callers do not depend on any specific backend.

type TokenBucket

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

TokenBucket is a token-bucket rate limiter: it refills tokens at a steady rate and allows bursts up to the configured capacity.

func NewTokenBucket

func NewTokenBucket(rate float64, burst int) *TokenBucket

NewTokenBucket returns a TokenBucket refilling rate tokens per second and allowing bursts of up to burst tokens.

func (*TokenBucket) Allow

func (b *TokenBucket) Allow() bool

Allow implements Limiter.

type TokenLimiter

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

TokenLimiter is a distributed token-bucket limiter with a local fallback: it normally consumes tokens from a shared Store, but when the store becomes unavailable it transparently degrades to an in-process limiter and resumes the store once it recovers. This prevents a remote-store outage from taking rate limiting down with it (cascading-failure protection).

func NewTokenLimiter

func NewTokenLimiter(rate, burst int, store Store, key string) *TokenLimiter

NewTokenLimiter returns a TokenLimiter consuming from store under key, refilling at rate tokens per second with bursts up to burst.

func (*TokenLimiter) Allow

func (l *TokenLimiter) Allow() bool

Allow reports whether a single request may proceed.

func (*TokenLimiter) AllowContext

func (l *TokenLimiter) AllowContext(ctx context.Context, n int) bool

AllowContext reports whether n requests may proceed, honoring ctx for the remote store call so a canceled request does not block on the store.

func (*TokenLimiter) AllowN

func (l *TokenLimiter) AllowN(n int) bool

AllowN reports whether n requests may proceed.

func (*TokenLimiter) Close

func (l *TokenLimiter) Close() error

Close stops the recovery monitor goroutine, if any. It is idempotent and safe to call when the limiter is no longer needed.

Directories

Path Synopsis
store
memory
Package memory provides an in-process ratelimit.Store.
Package memory provides an in-process ratelimit.Store.
redis
Package redis provides a Redis-backed ratelimit.Store using atomic Lua scripts, for distributed rate limiting across multiple instances.
Package redis provides a Redis-backed ratelimit.Store using atomic Lua scripts, for distributed rate limiting across multiple instances.

Jump to

Keyboard shortcuts

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