System design round

Design a Notification System

Sending one notification is an API call. Sending twenty thousand a second is a question about queues: the providers you depend on have hard limits, and a message that arrives too late is worse than none.

Estimate, draw your design, run its traffic through it and see which boxes break. Then answer the follow-up questions. The load test is free and needs no account; an AI review or score uses one of your AI replies.

The brief

It must

  • Other services publish events ("order 123 shipped"); the notification system decides who hears what.
  • Respect each user’s preferences: channels, quiet hours, language.
  • Send by push, SMS and email through outside providers.
  • A slow channel must not hold up the others. Delivery SMS more than three minutes late are worthless.

The numbers

  • Assume 20,000 order events a second for the first ten minutes of a sale.
  • Every event sends a push; 15% also send an SMS and half send an email.
  • Providers accept, a second: push 100,000, email 15,000, and SMS only 2,000.

Before you draw: the numbers

Interviewers expect a quick estimate first, because the numbers decide the design. Write yours, then check.

The load test uses round numbers per box, the kind you would use on a whiteboard, so it shows where a design breaks and roughly by how much, not exact figures. How it works

The follow-up questions

Once your design is up, the interviewer goes deeper. Each question changes one thing and is a level further, Fresher to Senior. An AI interviewer scores your answer; 6 out of 10 or more climbs the rung.

Notification system

Not climbed yet

Our design, and why

Try your own first. “Our design” on the board shows it as boxes you can load-test.

The numbers decide the design: 20,000 events a second become 20,000 pushes, 3,000 SMS and 10,000 emails, and the SMS provider takes 2,000 a second. No code makes that limit go away; the design decides what waits, where, and for how long.

  • Services publish events; only the notification service knows about providers. It reads preferences (from a cache: every event needs them), renders a template per channel, and queues one job per channel.
  • One queue per channel. In a shared queue, the SMS backlog would sit in front of push and email. Separate queues let each channel drain, retry and scale at its own pace.
  • Senders take jobs off their queue at the provider’s pace, retry with backoff, and record every attempt. A second SMS provider doubles capacity and covers an outage: switch when one’s error rate crosses a threshold.
  • Expiry on every message: a "your order is out for delivery" SMS three minutes late is noise. Drop it rather than deliver it.

Deduplicate before sending: a (event_id, channel) key with a unique constraint, or SET NX in Redis with a day’s expiry, so a producer bug that publishes "shipped" five times sends one message.

What each level is expected to cover

The AI review grades your board against these.

Fresher
  • A notification service between event producers and providers.
  • User preferences and templates per channel.
SDE 1
  • Queues between the service and the senders, with retries and backoff.
  • Recording the status of each attempt.
SDE 2
  • One queue per channel so a slow provider cannot delay others.
  • Provider rate limits: draining at their pace, a fallback provider, circuit breakers.
  • Expiry for time-sensitive messages.
Senior
  • Deduplication by event id and channel, and idempotency at the provider.
  • Priorities: OTPs and order updates ahead of marketing; per-user caps.
  • Large campaigns: precomputed audiences, batched fan-out, spreading sends over time.

How the load test works

Each round sends a few kinds of traffic from its users, at the rates in the brief. The test follows your arrows: a CDN answers what it can cache, a load balancer spreads requests, a service runs the logic and checks a cache beside it before the database, and a queue takes work off the request so the boxes after it work at their own pace.

Every box takes a rough number of requests a second (one service machine about 5,000, one Redis node about 100,000, one SQL primary about 3,000 writes, one row about 200 updates). A box asked for more turns red and drops the excess, unless a queue in front holds it back, in which case the queue grows and the work waits. Failure scenarios take machines away; a standby copy covers one.

It cannot see correctness: idempotency, consistency, and what users see when something fails. Write those in a box’s note; the AI review reads them.

blur