Documentation
¶
Overview ¶
Package throttle implements counter-based rate limiting for the auth surface, backed by the auth_throttle table. The model is fixed-window: each (scope, identifier) pair has a hit counter that resets when the window has elapsed.
We deliberately use Postgres rather than introducing Redis. At launch scale this is well within Postgres's comfort zone, and avoiding a new dependency is worth the marginal latency. Migrate if S36 proves it necessary.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func IsThrottled ¶
IsThrottled is the canonical predicate for distinguishing a throttle rejection from a generic error.
Types ¶
type DBTX ¶
DBTX matches sqlc's DBTX so callers can pass a *pgxpool.Pool or a transaction interchangeably.
type ErrThrottled ¶
ErrThrottled is returned by Hit when the policy's limit is exceeded. RetryAfter carries a hint suitable for the HTTP `Retry-After` header.
func (*ErrThrottled) Error ¶
func (e *ErrThrottled) Error() string
type Limit ¶
type Limit struct {
Scope string // e.g. "login", "signup", "reset"
Identifier string // e.g. "ip:1.2.3.4|alice"
Max int // hits permitted within Window
Window time.Duration // sliding-fixed window length
}
Limit is a (scope, identifier, max-hits, window) policy.
type Limiter ¶
type Limiter struct {
// contains filtered or unexported fields
}
Limiter holds the queries handle. Construct with NewLimiter.
func NewLimiter ¶
func NewLimiter() *Limiter
NewLimiter returns a limiter bound to the sqlc queries package.
func (*Limiter) Hit ¶
Hit increments the counter for the policy. Returns nil if under the limit, ErrThrottled (with RetryAfter) if at or over.
The query is conditional: if the existing window started before (now - policy.Window) we treat it as a new window and reset hits to 1. Otherwise we increment in place. The work happens atomically inside Postgres so concurrent requests don't undercount.