Documentation
¶
Overview ¶
Package subjectlimiter caps in-flight HTTP requests per authenticated subject. A single runaway or compromised client identity cannot saturate the proxy's goroutine or upstream connection pool at the expense of every other caller.
Memory: entries are reclaimed by a pruner goroutine when a subject has been idle for IdleEvictAfter, so the map size stays proportional to ACTIVE principals, not the lifetime set of ever-seen subjects. sync.Map keeps the hot path lock-free except on first-seen subjects.
Correctness: each entry stamps lastUsed at construction time so a prune tick landing between LoadOrStore and the caller's first Add cannot evict a fresh entry (which would let a concurrent request create a second semaphore and effectively double the per-subject cap). Entries with in-flight work (inFlight > 0) are never evicted.
Index ¶
Constants ¶
const ( // IdleEvictAfter is the window past which an entry with no // in-flight work is reclaimed by the pruner. 5 minutes covers the // longest realistic inter-request gap from a single MCP session // without letting orphaned entries linger forever. IdleEvictAfter = 5 * time.Minute // PruneInterval is the cadence at which the pruner goroutine scans // the map. Short enough to keep map size proportional to active // principals, long enough to keep the scan cheap. PruneInterval = 2 * time.Minute )
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Limiter ¶
type Limiter struct {
// contains filtered or unexported fields
}
Limiter caps concurrent requests per subject.
func New ¶
New creates a Limiter and wires a pruner goroutine to ctx so it exits on process shutdown. Callers use the Middleware method as an http middleware.
func (*Limiter) Middleware ¶
Middleware returns an http.Handler wrapper that rejects the request with 503 + Retry-After when the per-subject cap would be exceeded. Must run AFTER the auth middleware that sets ContextSubject.