Skip to content
Reliable Data Engineering
Practice problem medium sliding-windowdequedesign
Solve it in the browser (Python editor)

Sliding-Window Rate Limiter for an Ingestion API

Difficulty: Medium · Topics: sliding-window, deque, design · Asked at: Stripe, Cloudflare, Uber, Amazon

Problem

Implement RateLimiter(limit, window_s) with allow(client_id, ts) -> bool. A request is allowed if the client has made fewer than limit allowed requests in the half-open window (ts - window_s, ts]. Rejected requests don’t count. Timestamps per client are non-decreasing.

Starter code

class RateLimiter:
    def __init__(self, limit: int, window_s: float):
        pass

    def allow(self, client_id: str, ts: float) -> bool:
        pass

Hints

Hint 1

Per client keep a deque of allowed timestamps; evict those ≤ ts − window before deciding.

Solution

from collections import defaultdict, deque

class RateLimiter:
    def __init__(self, limit: int, window_s: float):
        self.limit = limit
        self.window = window_s
        self.hits = defaultdict(deque)

    def allow(self, client_id: str, ts: float) -> bool:
        q = self.hits[client_id]
        while q and q[0] <= ts - self.window:
            q.popleft()
        if len(q) < self.limit:
            q.append(ts)
            return True
        return False

Tests

Your solution should pass these:

rl = RateLimiter(limit=3, window_s=10)
assert [rl.allow("a", t) for t in (0, 1, 2, 3)] == [True, True, True, False]
assert rl.allow("b", 3) is True            # independent client
assert rl.allow("a", 9.9) is False
assert rl.allow("a", 10) is True           # ts 0 left the window (0 <= 10 - 10)
assert rl.allow("a", 11) is True
assert rl.allow("a", 11.5) is False

Explanation

Amortised O(1) per request (each timestamp is appended and popped once), O(limit) memory per client. Alternatives: fixed window counters (cheap, but allow bursts of 2× at window edges), token bucket (smooth rate, O(1) state per client, the usual production choice), and sliding window counter (approximate, interpolating two fixed windows). Distributed rate limiting needs shared state (Redis INCR + TTL or Lua scripts).