Documentation
¶
Index ¶
Constants ¶
const ( // MaxBuckets is the maximum number of rate limit buckets kept in memory. // When exceeded, stale buckets (fully refilled and older than their window) are evicted. MaxBuckets = 10000 )
Variables ¶
This section is empty.
Functions ¶
Types ¶
type BucketDelta ¶ added in v1.0.0
BucketDelta is a background adjustment to one bucket's remaining tokens. TokenAdjust is signed; a NEGATIVE value reduces the remaining tokens (used by the multi-node reconcile syncer to subtract other nodes' consumption from this node's local view so the cluster-wide limit is respected). It is applied by ApplyDeltas, never on the request path.
type BucketSnapshot ¶ added in v0.9.0
type BucketSnapshot struct {
Key string
Tokens int
Max int
Window time.Duration
LastRefill time.Time
}
BucketSnapshot is a point-in-time copy of one bucket's state, used by the persistence syncer for write-behind and boot restore. It carries the limiter's opaque key ("scope:tenant:agent"); the syncer parses the tenant out of it.
type Limiter ¶
type Limiter struct {
// contains filtered or unexported fields
}
Limiter implements a token-bucket rate limiter keyed by scope and agent.
func (*Limiter) Allow ¶
Allow checks whether a request identified by key is within the rate limit. maxRequests is the maximum number of requests allowed in the given window. Returns nil if allowed, or an error describing the limit.
func (*Limiter) ApplyDeltas ¶ added in v1.0.0
func (l *Limiter) ApplyDeltas(deltas []BucketDelta)
ApplyDeltas adjusts the remaining tokens of already-tracked buckets in bounded, chunked lock acquisitions. It is the write half of multi-node rate reconciliation and is called ONLY from the background syncer goroutine — never on the /v1/check hot path, so it cannot itself add hot-path latency.
Semantics (CLAUDE.md §1/§4 safe):
- Existing keys only. A delta whose key is not currently tracked is skipped; ApplyDeltas never synthesizes a bucket (it lacks max/window and doing so would let reconcile invent limits).
- Chunked locking: at most applyChunk (K≈128) buckets are touched per lock hold, so a concurrent Allow blocks for O(K) map ops, not O(n).
- Clamped to [0, max]: a negative adjust never drives remaining below zero; a (spurious) positive adjust never grants MORE than the bucket's capacity. For a firewall, granting above capacity would be a safety regression, so both ends are clamped even though reconcile only ever sends reductions.
- It does NOT touch lastRefill/window/max, so the fixed-window rollover math in Allow is unaffected; on the next window reset tokens return to max and the reconcile rebaselines for the new epoch.
func (*Limiter) BucketCount ¶ added in v0.5.0
BucketCount returns the current number of tracked buckets (for testing).
func (*Limiter) Restore ¶ added in v0.9.0
func (l *Limiter) Restore(snaps []BucketSnapshot)
Restore loads buckets from a prior Snapshot (boot hydration). Entries with a matching key are overwritten. Intended to run once, before serving traffic.
func (*Limiter) Snapshot ¶ added in v0.9.0
func (l *Limiter) Snapshot() []BucketSnapshot
Snapshot returns a copy of every live bucket. It holds the limiter lock only for the (O(n) struct-copy) duration and is intended for the background persistence syncer — it is never called on the request path, so it cannot affect the proxy's latency budget.