Ten million users need a green dot beside their name. What does that cost, and what happens when a phone loses signal without disconnecting?
Presence at 10 million users is a lease system, not a connection-state table. Clients renew short-lived keys, the dot expires when renewals stop, and the real cost is bounded fan-out to visible watchers rather than every contact.
What the interviewer is scoring
- Does the candidate treat presence as derived, expiring state rather than as a row to be updated and trusted
- Whether the half-open connection is raised before any storage choice is made
- That the fan-out cost is separated from the heartbeat cost, with arithmetic for each
- Can they justify a third state between online and offline instead of arguing for two
- Whether the answer bounds watchers to what is on screen rather than to a whole contact list
Answer
Short answer
Design presence as expiring leases, not as a boolean written on connect and disconnect. Each active device renews a short-lived presence key; if a phone loses signal and cannot disconnect cleanly, the lease expires and the dot turns off. The scaling problem is not just heartbeat writes, but fan-out to watchers, so subscribe only to users currently visible on screen and batch presence reads.
Mention ephemeral state where it changes the risk, the owner, or the next check. A useful ephemeral state point should make the answer more testable, not merely longer. Tie ephemeral state back to the scenario so the interviewer can see why it matters here.
The dot is a lease, and the tunnel proves it
Start with the failure, because it decides the data model. A phone goes into a tunnel. The radio drops. The TCP connection is not closed, because nobody got the chance to close it: no FIN, no RST, nothing. Your server still holds a socket it believes is a person. The dot stays green for as long as you trust that socket, which on a default keepalive can be many minutes.
So connection liveness cannot be the source of truth. Presence has to be a lease that the client renews and the server forgets. The client sends a heartbeat every few seconds; the server writes a key with a time-to-live a little longer than that interval; a user is online while their key exists. Nobody ever writes "offline". Offline is what expiry means.
That inversion is the whole answer. A design that flips a boolean on disconnect has to receive an event that a dying phone cannot send. A design built on expiry needs no event at all.
A hotel key card is the closest analogy. It stops working at checkout time whether or not you handed it back, so the hotel never depends on you returning it. The analogy breaks at the renewal step: a guest re-taps a card at the door when they want in, whereas your client has to renew on a timer even when the user is doing nothing, and that timer is what you are paying for.
What it costs, from a premise you state
Pick the numbers out loud. Ten million users, of whom say two million are connected at any moment, each renewing every thirty seconds. That is 2,000,000 / 30, so roughly 67,000 renewal writes a second. Each write is a small key with a TTL. An in-memory store handles that on a handful of nodes, sharded by user id, and none of it needs to be durable. If the store is wiped, every client renews within thirty seconds and the truth reassembles itself.
Now the other half, which is where these designs actually fail. Suppose each user has 200 contacts. Pushing every transition to every contact means each user going online generates 200 notifications. At a modest churn of 20,000 transitions a second that is four million notifications a second, and you have built a fan-out problem out of a dot.
The fix is to bound the watchers. A client subscribes to presence for the names currently rendered, which is a screenful — twenty or thirty people, not two hundred. When the list scrolls, the subscription changes. Contacts you cannot see cost nothing. That single decision moves the fan-out from the size of the social graph to the size of a viewport, and it is the number an interviewer is waiting to hear you bound.
Reads of presence should also be batched. One request carrying thirty user ids, answered from one shard-aware lookup, beats thirty requests. And presence is the cheapest possible thing to be slightly wrong about, so a two-second cache in front of it is free correctness-wise and removes most of the read load.
Three states, because two of them lie
Online and offline is not enough, and the reason is the heartbeat you are about to miss. Networks drop packets. A single missed renewal on a perfectly healthy phone would flip the dot to grey and back, and a flickering dot is read by users as a broken product.
Give yourself a middle state. Online means the lease is current. Away, or recently active, means the lease expired within the last few minutes and you are still willing to say something about them. Offline means longer than that. The middle state absorbs one lost heartbeat, one lift ride, and one app switch on a phone that suspends background sockets.
The transition to grey should also be debounced on the reading side. Hold the last known value for a few seconds before repainting, so a shard failover does not turn a page full of green dots grey and then green again. Users forgive presence being a few seconds stale. They do not forgive it strobing.
A strong candidate says something like: "I would rather be five seconds late marking someone offline than mark them offline twice."
Multiple devices, and the state you must not store
One user, several connections. Presence is then an aggregate: the user is online if any device's lease is current. That means the key is per device or per session, and the user-level answer is a fold over their sessions. Storing one lease per user and letting the laptop's expiry mark the phone offline is a defect users notice immediately, because it happens every time they close a lid.
Resist making any of this durable. "Last seen" is the one exception and it is a single timestamp per user, written on the transition out of online rather than on every heartbeat. That is one write per session, not one every thirty seconds. Writing last-seen on the heartbeat path turns a memory-resident workload into 67,000 durable writes a second for information nobody reads at that resolution.
Presence is also the most privacy-sensitive trivial feature in a product. Whether a user can hide, and whether the absence of a dot leaks that they hid, is a product decision that shows up in the data model as a per-viewer visibility check rather than as a global flag. Decide it before you build, because retrofitting it means every read path grows a permission lookup.
Where the answer usually goes wrong
Two mistakes account for most of it. The first is trusting the socket, which produces the tunnel bug and cannot be patched later without changing the model. The second is pushing every change to every contact, which works at ten thousand users and falls over at ten million, without any single component looking broken — the store is fine, the sockets are fine, and the notification volume is a multiple of the graph.
There is a third, quieter one. Treating presence as needing the same consistency as messages. It does not. It is derived state with a natural expiry and no history, and every design decision follows from accepting that being briefly wrong is the cheapest thing about it.
A dot that appears when a lease is renewed and vanishes when it lapses needs no disconnect event, which is the only property that survives a phone dropping off a network without saying goodbye.
© 2026 Preptima. Originally published at preptima.com.
Likely follow-ups
- A user is signed in on a phone and a laptop and closes the laptop. What does the dot do, and where is that decided?
- How would you serve "last seen 3 minutes ago" without storing a timestamp per user per second?
- The presence store loses a node holding two million leases. What do watchers see during the next thirty seconds, and is that the right thing?
- How does the design change if a user can appear invisible to some contacts and online to others?
Related questions
- One celebrity account is ninety per cent of your write traffic on a single partition. What do you do about a key you cannot rebalance?hardAlso on fan-out5 min
- Design the home feed for a social network.hardAlso on fan-out8 min
- The client retries a charge because your response timed out. The money must move once. What makes that true?hardAlso on expiry6 min
- Design the frontend for a data-heavy operational dashboard with live updates.hardAlso on websockets7 min