Skip to main content
Version: Next (unreleased)

Sliding Window

Both sliding window algorithms aim for "at most limit requests in any window-long stretch", without the fixed window's boundary burst. The log enforces it exactly; the counter estimates it, and can admit somewhat more than limit when traffic clusters around a window boundary.

Sliding window log​

SlidingWindow records the timestamp of every allowed request and counts those younger than window. It is exact: there is no approximation and no boundary effect.

// At most 5 attempts in any 15 minutes
limiter := ratelimit.NewSlidingWindow(5, 15*time.Minute)

The cost is memory proportional to limit, since it stores up to limit timestamps. That is the right trade for low limits where exactness matters — login attempts, password resets, OTP sends — and the wrong one for limits in the thousands.

The log has no keyed or Redis variant. For a per-key sliding window, use the counter below.

FieldValue
Limitlimit
Remainingrequests left in the trailing window
RetryAfterwhen denied, the time until the oldest request leaves the window
ResetAtwhen denied, the same moment as an absolute time; zero when allowed

limiter.Count() returns the number of requests currently in the window.

Sliding window counter​

SlidingWindowCounter keeps only two numbers: the count for the current fixed window and the count for the previous one. It estimates the trailing window by weighting the previous count by how much of it still overlaps:

estimate = previous × (1 − elapsed/window) + current

Twenty seconds into a one-minute window, a third of the way through, two thirds of the previous minute's requests still count.

// About 100 requests in any minute
limiter := ratelimit.NewSlidingWindowCounter(100, time.Minute)

The estimate assumes the previous window's requests were evenly spread. It is never off by more than the previous window's count, and in practice it is close — this is the algorithm Cloudflare and many API gateways use for exactly that reason. Memory is constant per key.

FieldValue
Limitlimit
Remaininglimit minus the weighted estimate
RetryAfterwhen denied, the computed time until the estimate leaves room
ResetAtthe end of the current underlying window

Per-key​

The keyed sliding window uses the counter algorithm:

limiter := ratelimit.NewKeyedSlidingWindow(100, time.Minute, 5*time.Minute)
defer limiter.Close()

limiter.Allow("user:42")

See Keyed Limiters.

Distributed​

redisstore.NewRedisSlidingWindow implements the counter algorithm in Redis. See Redis.