In a chat service, what should happen to a message whose recipient has no live connection, and what role should push notifications play?
answer
- durable before deliverable
- offline inbox is a cursor gap
- ack timer decides the branch
- a wake-up, not the payload
- collapse per conversation
basics
~20 sThe message is stored in the conversation log first, so it is waiting for the recipient no matter what. With no live connection, or no delivery ack before a timeout, the server hands off a push notification. That push only wakes the device, which then syncs from the server.
solid answer
~50 sStorage comes first. A message is **durably written** before any delivery is attempted, so an offline recipient loses nothing. The recipient's pending changes form an **offline inbox**: the change-feed entries and sequence numbers they have not acknowledged. Delivery then branches. With a live session, the server pushes the message and waits for a **device ack**. With no session, or no ack before a timeout, it emits a **push request** to the notification service. The push is treated as a **hint**, not as the data carrier: it may be delayed, merged with others or dropped. It carries at most a preview, a conversation ID and a sequence number, and on open the app syncs from its cursor. Two rules keep this honest. The "delivered" state changes only on a device ack, never on handing off a push. And push is suppressed for a device that is active and acking, so an online user does not receive duplicates.
go deeper
Remember that the server saves the message first, and that the push notification only tells the phone to come and fetch it.
Explain the delivery branch: live session with an ack timer, otherwise a push request, and why a device ack is the only proof of delivery.
Show the production details: collapsing pushes per conversation, suppressing push for active devices, badges computed from cursors, and tuning the ack timeout from measured latency.
Draw the boundary clearly: the chat service decides whether to request a push and what minimal data it carries, while the notification pipeline owns sending.
## The requirement A chat app has to work for someone who was offline for an hour. Nothing they were sent may be lost. They should learn that something arrived even though the app is not running. When they open the app, the history must be complete and in order. Those are three different jobs, and a common mistake is to make push notifications do all three. ## Store first, deliver second The durable **conversation log** is the source of truth. The server writes each message there and assigns its sequence number before attempting delivery. From that moment, an offline recipient has lost nothing. The message is waiting, and their per-user change feed shows that the conversation advanced. That set of unacknowledged changes is the recipient's **offline inbox**. Some designs also keep a small per-device pending queue, but it holds pointers into the log, not a second copy of the truth. ## The delivery decision 1. Look up whether the recipient has live sessions. Routing to the right gateway belongs to the connection tier. 2. **Live session**: push the message down the connection and start an ack timer. 3. **Device ack arrives**: mark the message as *delivered to that device*. No notification is needed. 4. **No session, or the timer expires**: emit a **push request** for that device to the notification service. 5. **User opens the app later**: the client syncs from its cursor and acks what it stores. | Signal | What it proves | May drive "delivered"? | |---|---|---| | Message written to the log | the server has it | no | | Push handed to the notification service | a wake-up was requested | no | | Device ack after local store | the device has it | yes | | Read cursor advanced | the user saw it | drives "read" | ## Push is a hint, not a transport Platform push services commonly **delay, merge or drop** notifications. This happens especially when a device is off or low on power. Some platforms also cap payload size. So the push payload should be small: a conversation ID, the latest sequence, maybe a short preview and a badge count. It is never the only copy. When the app wakes or opens, it **syncs from the server**, and missed or merged pushes cost nothing because the log is complete. - **Collapse per conversation**: ten messages in one chat produce one "10 new messages" notification, not ten buzzes. Collapse keys or coalescing in the hand-off make this possible. - **Badge from numbers**: compute the badge from the sequence numbers and read cursors, so it is right even when some pushes were dropped. - **Order is not implied**: pushes can arrive out of order, so the app orders by sequence number after syncing, never by push arrival. ## Avoiding duplicate and wrong notifications - **Suppress push for an active device**: if the device has acked recently and is in the foreground, the live connection has already shown the message. - **Clear on read elsewhere**: when the user reads the chat on another device, send a silent update so stale notifications can be removed. - **Deduplicate by sequence**: if both a push and a live message arrive, the client keeps one entry per `(conversation, seq)`. - **Do not over-trust the ack timeout**: a short timer on a slow link causes needless pushes, and a long one delays offline users. Tune it from measured ack latency. ## Where the edges are Once the push request leaves the chat service, it belongs to the notification pipeline: user preferences and quiet hours, templating, provider retries and failover. The chat service's job ends with deciding *whether* to request a push and *what minimal data* goes with it.
- Why should the "delivered" tick not flip when the push is handed off?Handing off a push only proves a wake-up was requested. The platform may delay or drop it, and the device may be off for days. Only a device ack sent after the message is stored locally proves delivery, so that ack is the only signal allowed to change the state.
- How do you keep an active user from getting a push for a message already on screen?Hand off a push only when the device has no live session or misses the ack timer. If a device acked recently and reports being in the foreground, suppress the push. When the chat is read on another device, send a silent update so notifications already shown can be cleared.
- Why should the push payload stay small?Pushes can be dropped or merged, and some platforms cap payload size, so the payload cannot be the only copy of the message. A conversation ID, a sequence number, a badge count and perhaps a short preview are enough to wake the app, which then pulls the full, ordered data from its sync cursor.
saying these in an interview costs you the question
- Put the full message in the push; that is how offline users receive it.
- Mark the message delivered once the push is sent.
- Keep undelivered messages only in the gateway's memory until reconnect.
- Send one push per message so users see each one.
- Order messages on the device by push arrival time.