Skip to main content
Version: Next (unreleased)

Fixed Window

Time is divided into windows of length window, and at most limit requests are allowed in each. The counter resets at the start of every window.

// 1000 requests per hour
limiter := ratelimit.NewFixedWindow(1000, time.Hour)

Windows are aligned to the clock​

Windows start at multiples of window (the start is time.Now().Truncate(window)), not at the first request, counted from the zero time in UTC. With time.Hour, every window starts on the UTC hour — at :30 or :45 local time in zones with a fractional offset — and every key resets at the same moment. That makes the limit easy to explain ("1,000 per clock hour") and easy to show in a UI, since ResetAt is predictable.

The boundary burst​

A client can spend its whole limit at the end of one window and its whole limit again at the start of the next. With 100 per minute, that is up to 200 requests in the two seconds around 12:00:00.

If that matters, use the sliding window counter, which smooths across the boundary at the same memory cost.

Result fields​

FieldValue
Limitlimit
Remainingrequests left in the current window
RetryAfterwhen denied, the time until the window ends
ResetAtthe end of the current window

Inspecting the window​

limiter.Count() // requests counted in the current window

Per-key​

limiter := ratelimit.NewKeyedFixedWindow(1000, time.Hour, 10*time.Minute)
defer limiter.Close()

limiter.Allow("api-key:abc")

See Keyed Limiters.

Distributed​

redisstore.NewRedisFixedWindow implements the same algorithm with windows aligned to Redis server time. See Redis.