ratelimit

package
v0.3.1 Latest Latest
Warning

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

Go to latest
Published: Oct 31, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package ratelimit supplies typed, atomic fixed-window admission decisions.

Index

Constants

View Source
const KeyFeature keyspace.Feature = "ratelimit"

KeyFeature is the physical address family owned by this adapter.

View Source
const MaxWindow = 24 * time.Hour

MaxWindow bounds live policy retention and retry durations.

Variables

This section is empty.

Functions

func ValidateClear

func ValidateClear(ctx context.Context, key Key) error

ValidateClear shares the adapter input boundary for ClearRateLimit.

func ValidateOperation

func ValidateOperation(ctx context.Context, key Key, limit Limit, cost uint32) error

Types

type Backend

type Backend interface {
	RateLimit(context.Context, Key, Limit, uint32) (Decision, error)
}

Backend owns one authority's clock and atomic fixed-window decisions. A live bucket with a different policy is converted to the requested one: admitted usage still counts (capped at the new capacity) and a new window starts on the new policy's phase. Denials consume nothing; a denied take persists only a conversion that ends later than the live bucket, so carried usage is never released early. Windows use Key.WindowOffset. A backward clock step inside a live bucket is clamped to that bucket's start instead of reopening quota or failing. Implementations honor cancellation, bound metadata reads and never implicitly retry a mutation or fall back to another authority. The caller owns the adapter lifecycle; network errors may leave consumption unconfirmed.

type Config

type Config struct {
	Namespace                                   keyspace.Namespace
	MaxKeyBytes, MaxDeclarations, MaxConcurrent int
	Timeout                                     time.Duration
}

Config bounds declaration count, logical key bytes and entire active operations, including key resolvers/codecs. Timeout uses real context deadlines. A burst beyond MaxConcurrent waits in FIFO order for at most admission.Wait(Timeout), within that same deadline, and then fails with fault.Overloaded.

func DefaultConfig

func DefaultConfig(namespace keyspace.Namespace) Config

func (Config) Validate

func (c Config) Validate() error

type Decision

type Decision struct {
	Allowed                bool
	Limit, Remaining       uint32
	ResetAfter, RetryAfter time.Duration
}

Decision reports the authority's decision at execution time. Denials consume no capacity. Durations are relative to that decision, not the client clock. An error always returns a zero Decision; never infer admission from an error.

func (Decision) Validate

func (d Decision) Validate(limit Limit, cost uint32) error

Validate checks adapter output against the exact policy and request cost.

func (Decision) ValidatePeek

func (d Decision) ValidatePeek(limit Limit, cost uint32) error

ValidatePeek checks non-consuming adapter output: Remaining is the capacity left now, Allowed reports whether cost fits it, and RetryAfter is zero when allowed or equals ResetAfter when not.

type Declaration

type Declaration[K any] struct {
	// contains filtered or unexported fields
}

Declaration preserves its resource key type and immutable policy. Reuse one declaration for a shared quota; distinct names intentionally isolate quotas.

func Define

func Define[K any](name Name, codec keyspace.Codec[K], limit Limit) Declaration[K]

func (Declaration[K]) Bind

func (d Declaration[K]) Bind(store *Store) (Limiter[K], error)

Bind rejects a different declaration with the same name, even with identical K.

func (Declaration[K]) Limit

func (d Declaration[K]) Limit() Limit

func (Declaration[K]) Name

func (d Declaration[K]) Name() Name

func (Declaration[K]) Validate

func (d Declaration[K]) Validate() error

type InspectBackend

type InspectBackend interface {
	PeekRateLimit(context.Context, Key, Limit, uint32) (Decision, error)
	ClearRateLimit(context.Context, Key) (bool, error)
}

InspectBackend is an optional Backend capability. PeekRateLimit reports the decision cost would receive now, using the same policy conversion and clock rules, without consuming capacity or changing expiry; see Decision.ValidatePeek. ClearRateLimit removes the key's bucket, including unreadable state at its address, so the next request starts a fresh window; true means state existed. Both follow Backend's cancellation, validation and no-retry rules.

type Key

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

Key is an opaque adapter address, distinct from cache and lease keys.

func NewKey

func NewKey(namespace keyspace.Namespace, name Name, logical string) (Key, error)

NewKey is for adapters and tests. Applications use a typed Limiter.

func (Key) Namespace

func (k Key) Namespace() keyspace.Namespace

func (Key) String

func (k Key) String() string

func (Key) Validate

func (k Key) Validate() error

func (Key) WindowOffset

func (k Key) WindowOffset(window time.Duration) time.Duration

WindowOffset is this key's deterministic window phase in [0, window). Adapters start fixed windows at offset + n*window, so the buckets of many keys do not all reset at the same Unix-epoch boundary. Every authority derives the same offset from the key address, independent of process or client clock. An uninitialized key or a nonpositive window has no phase.

type Limit

type Limit struct {
	Requests uint32
	Window   time.Duration
}

Limit admits Requests units per fixed Window. Each key's windows are shifted by its Key.WindowOffset, so many keys do not reset at the same instant. A fixed window permits bursts on both sides of a boundary; it is not a sliding window.

func PerHour

func PerHour(requests uint32) Limit

func PerMinute

func PerMinute(requests uint32) Limit

func PerSecond

func PerSecond(requests uint32) Limit

func (Limit) Validate

func (l Limit) Validate() error

func (Limit) ValidateCost

func (l Limit) ValidateCost(cost uint32) error

type Limiter

type Limiter[K any] struct {
	// contains filtered or unexported fields
}

Limiter consumes capacity using only its declaration's key type. Its zero value is invalid. Take is appropriate for weighted domain work; Allow costs one unit.

func (Limiter[K]) Allow

func (l Limiter[K]) Allow(ctx context.Context, key K) (Decision, error)

func (Limiter[K]) Attempt

func (l Limiter[K]) Attempt(ctx context.Context, key K, cost uint32, fn func(context.Context) error) (Decision, error)

Attempt takes cost and runs fn only when admitted, returning fn's error. A denial returns the decision without calling fn; an admission error returns it without calling fn. fn runs in the caller's goroutine after the bounded admission operation has finished, with the caller's context. Consumed capacity is not refunded when fn fails, and nothing is retried.

func (Limiter[K]) AvailableIn

func (l Limiter[K]) AvailableIn(ctx context.Context, key K, cost uint32) (time.Duration, error)

AvailableIn reports how long until cost could be admitted: zero when it fits now, otherwise the time until the current window resets. It consumes nothing.

func (Limiter[K]) Clear

func (l Limiter[K]) Clear(ctx context.Context, key K) (bool, error)

Clear removes the key's bucket so its next request starts a fresh window with full capacity. True means stored state existed. It also removes unreadable state at the key's address. Clearing grants new quota; use it deliberately (for example after a successful verification), never as error recovery.

func (Limiter[K]) Limit

func (l Limiter[K]) Limit() Limit

func (Limiter[K]) Name

func (l Limiter[K]) Name() Name

func (Limiter[K]) Peek

func (l Limiter[K]) Peek(ctx context.Context, key K, cost uint32) (Decision, error)

Peek reports the decision cost would receive now without consuming capacity or changing the bucket's expiry. Remaining is the capacity left now. It is an observation, not a reservation: a later Take can be denied. The backend must implement InspectBackend; otherwise Peek fails with fault.Invalid.

func (Limiter[K]) Remaining

func (l Limiter[K]) Remaining(ctx context.Context, key K) (uint32, error)

Remaining reports the capacity left in the key's current window without consuming it. A missing or expired bucket reports the full capacity.

func (Limiter[K]) Take

func (l Limiter[K]) Take(ctx context.Context, key K, cost uint32) (Decision, error)

func (Limiter[K]) TakeWith

func (l Limiter[K]) TakeWith(ctx context.Context, cost uint32, resolve func(context.Context) (K, error)) (Decision, error)

TakeWith resolves a concrete key inside the same bounded operation as encoding and admission. It catches panic/Goexit and waits for callback exit. The resolver must honor cancellation; no callback or uncertain command is automatically retried.

func (Limiter[K]) Validate

func (l Limiter[K]) Validate() error

type Name

type Name string

type Store

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

Store borrows its Backend. Construction performs no I/O or background work. Calls own callbacks until they actually exit, including after cancellation; an uncooperative callback retains its slot instead of creating detached work.

func NewStore

func NewStore(backend Backend, config Config) (*Store, error)

func (*Store) Namespace

func (s *Store) Namespace() keyspace.Namespace

Directories

Path Synopsis
Package memory implements explicit single-process fixed-window rate limiting.
Package memory implements explicit single-process fixed-window rate limiting.

Jump to

Keyboard shortcuts

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