Sliding window counter rate limiter.
Two counters per key and a weighted estimate fix the fixed window's boundary burst, in O(1) memory.
A fixed window counter lets a client send limit requests at 12:00:59 and limit more at 12:01:00: twice the limit in one second. The sliding window log fixes that but stores every timestamp. Day 3, section 2.3 gives the production sweet spot: keep only the count for the current fixed window and the previous one, and weight the previous count by how much of it still overlaps the sliding window.
window = int(now // window_seconds) # which fixed window we're in
position = now % window_seconds # seconds into it
prev_weight = (window_seconds - position) / window_seconds
estimate = prev_count * prev_weight + curr_countAllow the request when estimate < limit, and only then add 1 to curr_count.
Implement SlidingWindowCounterLimiter(limit, window_seconds, clock):
| Method | Returns |
|---|---|
is_allowed(key) |
True (and counts the request) or False (counts nothing) |
estimate(key) |
the weighted count right now, without counting a request |
Rules the tests check:
- When time moves into the next window, the current count becomes the previous count and the current count starts at 0.
- When time skips more than one window, the previous count is 0: nothing from two windows ago overlaps.
- Rejected requests are not counted.
- Store two counters per key, not timestamps.
- Read time only through
clock.now().
The lesson's worked example (limit 10 per 60 s): at 12:01:15 the previous minute had 8 requests and this minute has 3. The previous window still overlaps 45 of the last 60 seconds, so 8 × 0.75 + 3 = 9 < 10 and the request is allowed.
Write your code, then run 2 example tests and 9 hidden tests. Each run is limited to 8 seconds: an infinite loop gets stopped and Python restarts, your code stays.