Problem
Building a feed on read means querying and merging posts from everyone a user follows, which is slow and expensive for read-heavy products. Feeds are opened far more often than posts are created.
Also known as: push-model-feed, write-time-fan-out, timeline-precompute
Push new content into each follower feed at write time so reads are cheap.
Building a feed on read means querying and merging posts from everyone a user follows, which is slow and expensive for read-heavy products. Feeds are opened far more often than posts are created.
Fan-out on write, the push model, does the merging when content is created. Each follower's feed is a ready-to-read list. Fan-out on read, the pull model, does the opposite and merges at request time. Most large feed systems combine the two.
post created
├─ store post (id, author, body)
└─ enqueue fan-out(author, post_id)
worker: for follower in followers(author):
LPUSH feed:follower post_id
LTRIM feed:follower 0 799
read feed(user): ids = LRANGE feed:user 0 49; return hydrate(ids)
The feed stores only ids, so edits and deletes apply to a single post record; hydration filters out deleted posts. Workers fan out in chunks and in parallel, and they prioritize active followers first.
The hybrid threshold is typically defined by follower count. If an author has more than, say, 100000 followers, their posts are not pushed. At read time the service fetches the feed list and merges in the latest posts of followed high-fan-out authors, then sorts by time or rank.
Inactive users do not need materialized feeds. Skip them and rebuild on their next login from the pull path.
High: feed storage and fan-out workers
Medium: queues, lag monitoring, rebuilds
Medium: hybrid logic and consistency
Fan-out queue lag makes new posts appear late in feeds
A celebrity post saturates workers and delays everyone else
Deleted or edited posts remain visible in precomputed feeds