Practice a Notification Design Interview With Duplicate Events
Design notification handling around durable business identity, retries, uncertain provider outcomes and distinct user-visible delivery states.
TL;DR
- In this fictional notification exercise, define the user-visible promise before choosing delivery mechanics.
- Separate event receipt, logical notification, delivery attempt, and known or uncertain outcome.
- Test duplicates and timeouts across provider behavior, preferences, and multiple devices.
Start with the user-visible promise
In this fictional design interview, a collaboration app sends a notification when a report is ready. The event queue may deliver the same event more than once, users can have several devices, and a notification provider can time out after accepting a request. The interviewer asks how you would prevent duplicate notifications.
Clarify the promise before drawing the queue. Does the product want one notification record per report, one alert per device or at most one interruption across all devices? These are different requirements. A unique database row can establish one logical notification without proving that a user saw exactly one banner.
Also distinguish a new report version from a repeated event for the same version. Deduplicating only by report ID could suppress a legitimate later update. The identity should reflect the business event the user is supposed to learn about.
Draw the states separately
Use a simple state model for the practice discussion: event received, logical notification recorded, delivery attempted and outcome known or uncertain. Do not collapse these into one “sent” boolean.
| Record | What it establishes | What it does not establish |
|---|---|---|
| Event receipt | The service observed an event | A user was notified |
| Notification identity | The business notification exists | Every device received it |
| Provider acceptance | The provider accepted a request | The user read it |
| Application read state | A recorded user interaction | Every external alert disappeared |
Define a stable identity such as recipient plus event type plus report version, with an appropriate uniqueness constraint. Persist the logical notification before treating the queue message as successfully handled. Describe the transaction boundary rather than merely saying “use a deduplication cache.”
Work through the uncertain timeout
Suppose a worker sends a request and loses the response. The provider may have accepted it. Retrying can create another delivery, while never retrying can lose the alert if the first request failed. The system needs an explicit policy for this uncertainty.
If the provider supports a relevant idempotency mechanism, explain its scope and retention limits after checking its contract. Do not assume every channel provides the same guarantee. Otherwise, distinguish a durable in-app notification from a best-effort external alert and explain the duplicate-versus-loss tradeoff for the product.
A lease can stop two workers from intentionally processing the same job simultaneously, but it does not erase an external request whose result is unknown. A worker can crash after the provider accepts the request and before the application records that fact. Mentioning this boundary makes the answer more credible than promising universal exactly-once delivery.
Decide what can be collapsed
A latest-status update may replace an older status notification, while separate messages may each need to remain visible. The Firebase documentation on collapsible messages distinguishes those cases and states that FCM does not guarantee delivery order. Use the provider's actual behaviour rather than assuming a queue order is preserved through the entire path.
For the fictional report product, a push could tell the app to fetch current notification state. The durable state remains authoritative even if the alert arrives late. If the user opens a completed report after a newer version exists, the interface should explain the current state rather than blindly trusting an old payload.
This is a design option, not a claim that collapsing is correct for every notification. A security alert or individually meaningful message may require a different policy.
Include preferences and multiple devices
Determine when preferences are evaluated. A queued marketing-like alert might need to respect a preference change before dispatch, while a required service message may follow a different product policy. State the policy rather than treating all notifications alike.
For multiple devices, decide whether read state is account-wide and how devices learn about it. Clearing an in-app unread badge is separate from withdrawing an already displayed operating-system notification. Avoid promising control the platform does not provide.
Keep observability keyed to the logical notification and individual attempts. This allows support to distinguish repeated events, retries and multiple legitimate device deliveries. Our system design frameworks guide can help keep these boundaries visible in the interview diagram.
Test the failure sequence
Ask a partner to inject four events: duplicate queue delivery, worker crash after provider acceptance, a preference change while queued and an older update arriving after a newer one. Walk each through the records and policies you chose.
The answer is incomplete if every failure is handled by “retry” without explaining identity or uncertainty. It is also incomplete if deduplication suppresses future legitimate report versions.
Finish with a precise statement of what the system guarantees and what it observes only indirectly. Practise a shorter explanation using the mock interview strategy. A strong design separates the durable user-facing record from channel delivery attempts and does not confuse provider acceptance with human attention.