Documentation
¶
Overview ¶
Package ratelimit is cadish's in-memory, per-node token-bucket rate limiter — the stateful server-side half of the native `rate_limit` security primitive.
Architecture (WAF v1b / D51):
- The PURE pipeline gate (internal/pipeline.EvalSecurity) identifies the applicable rate_limit rule for a request and computes the bucket KEY (the resolved real client IP, a header value, or a whole-site constant). It does NO counting — it stays a side-effect-free function safe for concurrent use.
- This package owns the MUTABLE state: one token bucket per (rule, key). The server consults Allow(key, rule) in the gate seam after `deny`; on a throttle it returns 429 + Retry-After, touching neither cache nor origin.
State is PER-NODE only (spec §2.7 / D51): no distributed counters, no Redis, no gossip. With N nodes behind an LB each counts independently, so the effective limit is ≈ N× the configured rate — mitigate by setting limit = target/N.
The store is SHARDED by key hash so concurrent requests on different keys do not contend on a single global lock, and idle buckets are swept on a background timer so memory stays bounded under a high-cardinality key space (e.g. per-IP buckets during a botnet flood). The clock is injectable so the token math is testable without sleeping.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func RetryAfterSeconds ¶
RetryAfterSeconds rounds a Retry-After hint up to whole seconds (minimum 1), the form the HTTP Retry-After header takes for a delta value.
Types ¶
type Decision ¶
Decision is the outcome of an Allow call. OK is false when the request is throttled; RetryAfter is then the time until the next token is available (a hint for the 429 Retry-After header; the server rounds it up to whole seconds).
type Limiter ¶
type Limiter struct {
// contains filtered or unexported fields
}
Limiter is a sharded, in-memory, per-node token-bucket rate limiter. Construct with New (real clock) or NewWithClock (injectable clock, for tests). Safe for concurrent use. Call Stop to halt the background sweeper.
func New ¶
func New() *Limiter
New builds a Limiter using the wall clock and starts its background sweeper.
func NewWithClock ¶
NewWithClock builds a Limiter with an injectable time source (tests pass a fake clock so token refill is deterministic without sleeping) and starts the sweeper.
func (*Limiter) Allow ¶
Allow consumes one token for key under rule and reports whether the request is admitted. A nil Limiter always admits (defensive: a server with no rate_limit rules holds a nil limiter and never calls this).