Skip to main content

359. Logger Rate Limiter

easyAsked at Twilio

Logger Rate Limiter is Twilio's signature rate-limit warm-up: implement shouldPrintMessage(timestamp, message) that returns true iff the message hasn't been printed in the last 10 seconds. Twilio's API-platform interviews use this as the entry point to the full rate-limiter design family. The grading bar is the hash-map approach with O(1) per call.

By Alex Chen, Founder, InterviewChamp.AI · Last verified

Source citations

Public interview reports confirming this problem appears in Twilio loops.

  • Glassdoor (2026-Q1)Heavily-cited in Twilio API-platform and developer-experience on-site reports as a domain-aligned question.
  • LeetCode Discuss (2025-12)Recurring in Twilio interview reports — explicitly named as 'rate-limit-style' question.

Problem

Design a logger system that receives a stream of messages along with their timestamps. Each unique message should only be printed at most every 10 seconds (i.e., a message printed at timestamp t will prevent other identical messages from being printed until timestamp t + 10). All messages will come in chronological order. Several messages may arrive at the same timestamp. Implement the Logger class: Logger() initializes the logger object; bool shouldPrintMessage(int timestamp, string message) returns true if the message should be printed in the given timestamp, otherwise returns false.

Constraints

  • 0 <= timestamp <= 10^9
  • Every timestamp will be passed in non-decreasing order (chronological order).
  • 1 <= message.length <= 30
  • At most 10^4 calls will be made to shouldPrintMessage.

Examples

Example 1

Input
shouldPrintMessage(1, "foo"), shouldPrintMessage(2, "bar"), shouldPrintMessage(3, "foo"), shouldPrintMessage(8, "bar"), shouldPrintMessage(10, "foo"), shouldPrintMessage(11, "foo")
Output
[true, true, false, false, false, true]

Approaches

1. Hash map of next-allowed timestamps (canonical optimal)

Store message -> next-allowed-timestamp. On each call, allow if current >= next-allowed; update next-allowed = current + 10.

Time
O(1) per call
Space
O(distinct messages)
class Logger {
  constructor() {
    this.nextAllowed = new Map();
  }
  shouldPrintMessage(timestamp, message) {
    const allowedAt = this.nextAllowed.get(message);
    if (allowedAt !== undefined && timestamp < allowedAt) return false;
    this.nextAllowed.set(message, timestamp + 10);
    return true;
  }
}

Tradeoff: O(1) lookup and update. Memory grows with distinct messages — never shrinks. The optimal answer for the LC contract but production-fragile (memory leak for unbounded message space).

2. Sliding window queue + set (memory-bounded alternative)

Maintain a queue of (timestamp, message) and a set of messages in the window. On each call, evict expired entries from the queue head, then check the set.

Time
amortized O(1) per call
Space
O(messages in last 10s)
class LoggerBounded {
  constructor() {
    this.queue = []; // [timestamp, message]
    this.window = new Set();
  }
  shouldPrintMessage(timestamp, message) {
    // Evict expired
    while (this.queue.length > 0 && this.queue[0][0] + 10 <= timestamp) {
      const [_, msg] = this.queue.shift();
      this.window.delete(msg);
    }
    if (this.window.has(message)) return false;
    this.queue.push([timestamp, message]);
    this.window.add(message);
    return true;
  }
}

Tradeoff: Memory bounded by the number of messages in the active 10-second window — won't leak under unbounded message space. Amortized O(1) per call. Queue.shift() is O(n) in JS arrays; use an index pointer for production. This is the answer Twilio interviewers actually want when they extend to 'how do you handle unbounded message identifiers?'

Twilio-specific tips

Twilio's API platform team explicitly uses this question to grade rate-limiter intuition. State both approaches AND the memory tradeoff. The hash-map version is cleaner code; the queue+set version is what you'd ship to production. Be ready for the follow-up 'now generalize to N requests per K seconds' (LC 1188 — Logger Rate Limiter II or 933 — Number of Recent Calls) — the queue+set extends naturally, the hash-map doesn't.

Common mistakes

  • Using `<` instead of `>=` for the timestamp comparison — at exactly t + 10 the message SHOULD print, not be blocked.
  • Forgetting to update next-allowed when a message is allowed — defeats the rate limit on repeat messages.
  • Returning false-as-side-effect by updating the timestamp even when blocked — extends the block window incorrectly past the original 10 seconds.

Follow-up questions

An interviewer at Twilio may pivot to one of these next:

  • Generalize to N calls per K seconds per user (LC 1188). (Use queue+set per user, drop expired on each call.)
  • What if timestamps could arrive out of order? (Stable sort by timestamp on a sliding buffer; or use an interval tree.)
  • How would you adapt this to a distributed rate-limiter across N machines? (Token bucket in Redis with atomic INCR + EXPIRE, or a shared sliding-window log.)

Solve it now

Free. No sign-up. Python and JavaScript run instantly in your browser.

Output

Press Run or Cmd+Enter to execute

FAQ

Why is the hash-map version called 'production-fragile'?

Because keys never get evicted. If your message space is unbounded — e.g., distinct request IDs — the map grows without bound for the lifetime of the process. The queue+set version self-cleans because the set membership is gated on a moving time window.

How does this relate to Twilio's actual rate-limiting code?

Public Twilio engineering posts describe their rate-limiting stack as token-bucket per route + sliding-window log per user. The Logger Rate Limiter problem is a minimal version of the sliding-window log — the same data structure scales up to per-user, per-endpoint, multi-region production rate limiters.

Free learning resources

Curated free links for this problem.

Practice these live with InterviewChamp.AI

Drill Logger Rate Limiter and other Twilio interview questions under real-loop conditions with instant feedback on your reasoning, complexity claims, and code.

Practice these live with InterviewChamp.AI →