Build a User Action Rate Limiter
Implement a RateLimiter class that tracks how many actions each user has taken within a sliding time window.
Each call to is_allowed asks: should this user's action go through? The answer is yes if fewer than max_actions actions have been recorded for that user in the last window_seconds seconds — and no otherwise. If the action is allowed, record it.
A timestamp that is exactly window_seconds old has just expired and does not count.
- Implement a
RateLimiterclass inmain.py. RateLimitermust have anis_allowed(self, user_id, timestamp, max_actions, window_seconds)method that returnsTrueorFalse.- Return
True(and record the action) if the user has taken fewer thanmax_actionsactions in the half-open window[timestamp - window_seconds, timestamp). - Return
False(and do not record the action) if the user is at or over the limit. - Each user has their own independent action history — one user being rate-limited must not affect another.
- The first action by any user must always be allowed.
max_actions=2, window_seconds=10
is_allowed('alice', 0, 2, 10)
is_allowed('alice', 5, 2, 10)
is_allowed('alice', 8, 2, 10)True True False
At t=8, both t=0 and t=5 are within the 10-second window (8-0=8 < 10, 8-5=3 < 10). Alice already has 2 recorded actions — she's at the limit.
max_actions=2, window_seconds=10
is_allowed('alice', 0, 2, 10)
is_allowed('alice', 5, 2, 10)
is_allowed('alice', 10, 2, 10)True True True
At t=10, the t=0 action is exactly 10 seconds old (10-0=10), so it has expired and is no longer in the window. Only t=5 remains — Alice is below the limit.
max_actions=3, window_seconds=60
is_allowed('alice', 0, 3, 60)
is_allowed('alice', 1, 3, 60)
is_allowed('alice', 2, 3, 60)
is_allowed('bob', 0, 3, 60)True True True True
Alice's limit has no effect on Bob — each user's history is tracked separately.
- Timestamps are non-negative integers (Unix seconds). They will be passed in non-decreasing order within a single test.
- Do not use any external libraries — a plain Python
dictis all you need. max_actionsandwindow_secondsmay differ between calls — handle them dynamically, not by hardcoding.
This implementation stores every timestamp forever. In production, you'd want to prune old entries so memory doesn't grow without bound. Where exactly would you prune, and what data structure would make it fastest?
Keep moving through related algorithms & data structures problems and build a stronger search-friendly practice loop around this topic.
View track →