When a post is deleted or a user unfollows someone in a fanout-on-write home timeline, how do stale entries get out of followers' inboxes?
answer
- undo is another fanout
- who enforces correctness
- tombstone during hydration
- author ID per entry
- race with in-progress fanout
basics
~10 sCorrectness comes from read-time filtering: hydration drops deleted posts and entries from unfollowed or blocked authors. Asynchronous cleanup then removes entries from inboxes, and truncation ages out anything cleanup misses.
solid answer
~50 sCleanup in a push timeline is itself a fanout, so it is slow and can race with the original fanout; the design therefore never relies on it for correctness. On every read, **hydration filters** entries: a deleted post resolves to a tombstone or nothing and is dropped, and entries whose author is no longer followed or is blocked are skipped by checking the current relationship. Then **asynchronous cleanup** removes entries: an unfollow touches only one inbox, so it is cheap and done promptly; a delete from an author with many followers costs as much as the original fanout, so some systems do it in low priority or skip it and let **truncation** age the entry out. Fanout workers should also check the post's status before writing, so a delete that lands mid-fanout is not undone. A refollow needs a small backfill of that author's recent posts.
go deeper
Recall that inboxes hold copies of post IDs, so deleting or unfollowing leaves stale copies that something must hide or remove.
Explain the read-time filter during hydration and why storing author IDs in entries makes unfollow cleanup cheap.
Walk through the delete-during-fanout race and the three layers: filter on read, async cleanup, truncation as the backstop.
Argue which invalidations need urgency guarantees, such as blocks and privacy, and where skipping cleanup is an acceptable cost trade.
## Why this is harder than it looks In **fanout-on-write**, a post ID is copied into the precomputed inbox of every follower. Anything that later invalidates that copy needs its own fanout to undo it: - a **post delete** must remove one ID from potentially millions of inboxes; - an **unfollow** must remove one author's entries from one inbox; - a **block** or a **privacy change** must stop content from appearing, sometimes with legal or safety urgency. Undo fanout is asynchronous, can lag, and can race with fanout still in progress. So the core design rule is: **the read path enforces correctness; cleanup only reclaims space.** ## Layer 1: filter at read time Every timeline read already hydrates post IDs into posts. That step is the natural place to filter: - **Deleted posts.** The post store returns a tombstone or no record, and the entry is dropped. - **Unfollowed authors.** If inbox entries carry the author ID, the read compares it against the reader's current follow set and skips mismatches. - **Blocked or hidden authors.** Checked against the reader's block and mute lists on every read. - **Visibility changes.** A post made private is filtered by its current visibility, not by the state at fanout time. Filtering shrinks pages, so the read path **over-fetches** a few extra IDs and trims after filtering. ## Layer 2: clean up asynchronously Cleanup keeps inboxes from filling with dead entries that push live ones past the cap. | Event | Inboxes touched | Typical handling | |---|---|---| | Unfollow | One (the unfollower's) | Remove that author's entries promptly | | Block | One or two | Remove entries promptly; read filter covers the gap | | Delete, small audience | Few | Run an undo fanout | | Delete, huge audience | Millions | Low-priority undo fanout, or rely on truncation | | Refollow | One | Backfill the author's recent posts into that inbox | For pulled high-follower accounts in a hybrid design, a delete is trivial: the post is removed from the account's own outbox, and no inbox holds it. ## Layer 3: truncation as a safety net Inboxes are trimmed to the most recent N entries, so a stale entry that cleanup missed is pushed out as newer posts arrive. This bounds how long garbage can linger, which is why skipping undo fanout for huge deletes is acceptable **only because** the read filter already hides the post. ## The race to design for Consider a post by an author with 2 million followers: 1. Fanout starts and has written to 800,000 inboxes. 2. The author deletes the post; an undo job starts and walks the same follower list. 3. The undo job finishes its pass while fanout is still writing to the remaining inboxes. The result is that some inboxes receive the ID after cleanup passed them. Mitigations: - fanout workers **check the post's status** before each batch and abort once it is deleted; - the read filter hides the post regardless; - truncation eventually removes the entry. ## Unfollow and refollow details - An unfollow cleanup scans one inbox for entries by that author; storing the author ID per entry makes this cheap. - If a user unfollows and refollows quickly, the cleanup and the backfill must be ordered, otherwise the backfill can be wiped. Versioning the follow edge (for example a follow timestamp) lets each job check it is still current. - A new follow only affects future fanout, so without a **backfill** the new author's recent posts are absent until they post again. ## What to say in an interview - Never promise that the undo fanout is the correctness mechanism. - Name the read-time filter first, then cleanup, then truncation. - Note that blocks and privacy changes must be enforced at read time because of their urgency.
- Why is it acceptable to skip the undo fanout for a delete by an author with millions of followers?Because the read path already filters the deleted post during hydration, so no reader sees it. The stale ID only wastes a slot in each inbox, and inbox truncation pushes it out as new posts arrive. Skipping it trades a little wasted space for avoiding a job as expensive as the original fanout.
- What goes wrong if a user unfollows and immediately refollows an author?Two async jobs run close together: a cleanup removing the author's entries and a backfill inserting their recent posts. If the cleanup runs last, the refollowed author's posts vanish from the inbox. Checking a version or timestamp on the follow edge lets each job confirm it is still current before acting.
saying these in an interview costs you the question
- Deleting a post synchronously removes it from every inbox before responding.
- The undo fanout alone guarantees deleted posts never appear.
- Unfollows are as expensive to clean up as deletes.
- A block can wait for asynchronous cleanup to take effect.
- A new follow automatically shows the author's older posts.