class NotificationRateLimiter:
The round: a Cursor coding screen (the second round in one report): write a notification rate limiter and run it on real test cases. Two reports, March and July 2026. In one, the interviewer runs real test cases and you write the code and verify it; the follow-up grows it into a rate limiter system design, and that candidate failed because time ran out before the design was complete. In the other, part 2 makes the limiter extensible.
The limits: both reports have the same three levels, user, team and company. One gives the numbers: a user may send at most 3 notifications in 10 minutes, a team at most 10, a company at most 20. The other says a helper is given that returns a user's team and company, and that when the call returns True the notification is counted.
Given here: a helper, lookup, takes a user id and returns (team_id, company_id); the constructor receives it. Timestamps are seconds and arrive in order; 10 minutes is 600 seconds, and a send counts against the window while it is less than 600 seconds old. The units and that boundary are ours, so ask; the tests stay clear of the exact boundary.
Part 1 — three-level limits: NotificationRateLimiter(lookup) with can_send_notification(user_id, timestamp). Return True and count the notification at the user, team and company levels if all three limits allow it; return False and count nothing if any level is full. One report names it should_send_notifications.
The approach one candidate used: an outward-facing register_handler(handler); each new rule is a handler, and the core of can_send_notification stays unchanged. The interviewer gives example rules, such as 'a user may send at most 4 messages of 50 length per minute', and the point of the part is a pluggable design so later rules need no change to the core code.
Standard explanation — no candidate report records what the interviewer accepted here.
Discuss distributed counters/storage (e.g., Redis), consistency tradeoffs, latency, and coordination across service instances.
You write the code and run it through real test cases. One candidate's base solution: a deque of timestamps per user, team and company, pruning entries older than the window before each check; if the notification is allowed, count it.
Two reports. Write the three-level limiter and run it on real test cases; then either extend it (a message_size parameter and pluggable rules) or grow it into a rate limiter design. One candidate failed because time ran out before the design part was complete.
The round: a Cursor coding screen (the second round in one report): write a notification rate limiter and run it on real test cases. Two reports, March and July 2026. In one, the interviewer runs real test cases and you write the code and verify it; the follow-up grows it into a rate limiter system design, and that candidate failed because time ran out before the design was complete. In the other, part 2 makes the limiter extensible.
The limits: both reports have the same three levels, user, team and company. One gives the numbers: a user may send at most 3 notifications in 10 minutes, a team at most 10, a company at most 20. The other says a helper is given that returns a user's team and company, and that when the call returns True the notification is counted.
Given here: a helper, lookup, takes a user id and returns (team_id, company_id); the constructor receives it. Timestamps are seconds and arrive in order; 10 minutes is 600 seconds, and a send counts against the window while it is less than 600 seconds old. The units and that boundary are ours, so ask; the tests stay clear of the exact boundary.
Part 1 — three-level limits: NotificationRateLimiter(lookup) with can_send_notification(user_id, timestamp). Return True and count the notification at the user, team and company levels if all three limits allow it; return False and count nothing if any level is full. One report names it should_send_notifications.
Part 2 — message_size and pluggable rules: ExtensibleRateLimiter(lookup) builds on Part 1. can_send_notification(user_id, timestamp, message_size=0) takes the new parameter, and register_handler(handler) adds a rule without changing the class. The interviewer gives example rules, such as "a user may send at most 4 messages of 50 length per minute"; the point is that a new rule never touches the core code. Here a handler is any object with two methods, allows (given req, returns True or False) and record (given req), where req is a dict with user_id, team_id, company_id, timestamp and message_size; that protocol is ours. A send goes through only if the three limits and every handler allow it, and only then is it counted and recorded by every handler.
How would you turn this into a full distributed rate limiter system design?
How would you extend this to support arbitrary new rules (e.g., 'user can send at most 4 messages of 50 chars per minute') without modifying the core code?
Walk me through real test cases and verify your implementation produces the correct output.
| Approach | Notes |
|---|---|
| Fixed window counter | Simpler to implement but less accurate at window boundaries; interviewers appear to expect a sliding window approach given the deque hint. |
| Token bucket | Well-known rate limiting algorithm; supports burst traffic more naturally, but adds complexity and wasn't the approach mentioned by candidates who passed. |
Common mistakes: Running out of time: one candidate failed because time ran out before the design extension was complete.
Interviewer hints: The interviewer explicitly described concrete new rule examples (e.g., 'user may send at most 4 messages of 50 characters per minute') to prompt the candidate to think about extensibility without modifying the core code.
What passers do: One candidate's approach: a deque per user, team and company, pruning expired timestamps before each check; then register_handler for the pluggable rules.
Why people fail: Ran out of time before completing the extension/system design portion; Could not produce a working, bug-free implementation that passed all test cases within the allotted time; Proposed a design for extensibility that still required modifying core rate limiter code to add new rules
Edge cases probed: Notifications at exactly the boundary of the 10-minute window (expiry edge); Multiple users in the same team hitting the team limit while individual user limits are not yet reached; Multiple teams in the same company hitting the company limit; A notification that should be rejected at the company level even though user and team limits are fine; Adding new rate limit rules without touching core code (extensibility boundary)