{"type":"excalidraw","version":2,"source":"https://AwesomeSystemDesign.dev","elements":[{"angle":0,"strokeColor":"#6577aa","backgroundColor":"#eef1fc","fillStyle":"solid","strokeWidth":1.5,"strokeStyle":"solid","roughness":0.7,"opacity":100,"version":1,"versionNonce":1,"isDeleted":false,"groupIds":["step-1"],"frameId":null,"roundness":null,"boundElements":[{"type":"text","id":"shape-1"}],"updated":0,"link":null,"locked":false,"id":"shape-0","type":"rectangle","seed":41,"x":466,"y":32,"width":390,"height":223.20000000000002,"customData":{"revealStep":1}},{"angle":0,"strokeColor":"#394557","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":1.5,"strokeStyle":"solid","roughness":0.7,"opacity":100,"version":1,"versionNonce":1,"isDeleted":false,"groupIds":["step-1"],"frameId":null,"roundness":null,"boundElements":null,"updated":0,"link":null,"locked":false,"id":"shape-1","type":"text","seed":114,"x":486,"y":50,"width":350,"height":187.20000000000002,"fontSize":18,"fontFamily":1,"text":"Client makes GET /feed/stream\nServer holds connection open until\nnew post arrives\nor timeout (30s).\n\n+ Lower latency than polling\n+ Fewer empty responses\n- Still one connection per client","originalText":"Client makes GET /feed/stream\nServer holds connection open until\nnew post arrives\nor timeout (30s).\n\n+ Lower latency than polling\n+ Fewer empty responses\n- Still one connection per client","textAlign":"center","verticalAlign":"middle","containerId":"shape-0","lineHeight":1.3,"autoResize":false,"customData":{"revealStep":1}},{"angle":0,"strokeColor":"#628572","backgroundColor":"#edf5ee","fillStyle":"solid","strokeWidth":1.5,"strokeStyle":"solid","roughness":0.7,"opacity":100,"version":1,"versionNonce":1,"isDeleted":false,"groupIds":["step-2"],"frameId":null,"roundness":null,"boundElements":[{"type":"text","id":"shape-3"}],"updated":0,"link":null,"locked":false,"id":"shape-2","type":"rectangle","seed":187,"x":36,"y":32,"width":390,"height":433.8,"customData":{"revealStep":2}},{"angle":0,"strokeColor":"#394557","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":1.5,"strokeStyle":"solid","roughness":0.7,"opacity":100,"version":1,"versionNonce":1,"isDeleted":false,"groupIds":["step-2"],"frameId":null,"roundness":null,"boundElements":null,"updated":0,"link":null,"locked":false,"id":"shape-3","type":"text","seed":260,"x":56,"y":50,"width":350,"height":397.8,"fontSize":18,"fontFamily":1,"text":"Client polls GET\n/feed/new?since={last_post_id}\nevery 30 seconds.\n\nServer: check if new posts exist in\nfeed cache\nsince last_post_id.\n\nIf yes: return count (\"3 new\ntweets\")\nUser taps to load them.\n\n+ Simple, works at scale\n- 30s delay, many empty polls\n- 500M users polling = 16M req/sec\n(but most users aren't actively\nwatching feed)","originalText":"Client polls GET\n/feed/new?since={last_post_id}\nevery 30 seconds.\n\nServer: check if new posts exist in\nfeed cache\nsince last_post_id.\n\nIf yes: return count (\"3 new\ntweets\")\nUser taps to load them.\n\n+ Simple, works at scale\n- 30s delay, many empty polls\n- 500M users polling = 16M req/sec\n(but most users aren't actively\nwatching feed)","textAlign":"center","verticalAlign":"middle","containerId":"shape-2","lineHeight":1.3,"autoResize":false,"customData":{"revealStep":2}},{"angle":0,"strokeColor":"#a68a53","backgroundColor":"#fff7e6","fillStyle":"solid","strokeWidth":1.5,"strokeStyle":"solid","roughness":0.7,"opacity":100,"version":1,"versionNonce":1,"isDeleted":false,"groupIds":["step-3"],"frameId":null,"roundness":null,"boundElements":[{"type":"text","id":"shape-5"}],"updated":0,"link":null,"locked":false,"id":"shape-4","type":"rectangle","seed":333,"x":466,"y":505.8,"width":390,"height":176.4,"customData":{"revealStep":3}},{"angle":0,"strokeColor":"#394557","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":1.5,"strokeStyle":"solid","roughness":0.7,"opacity":100,"version":1,"versionNonce":1,"isDeleted":false,"groupIds":["step-3"],"frameId":null,"roundness":null,"boundElements":null,"updated":0,"link":null,"locked":false,"id":"shape-5","type":"text","seed":406,"x":486,"y":523.8,"width":350,"height":140.4,"fontSize":18,"fontFamily":1,"text":"Full-duplex persistent connection.\nServer pushes new posts in real-time.\n\n+ Lowest latency, bidirectional\n- Expensive at scale (millions of\nconnections)","originalText":"Full-duplex persistent connection.\nServer pushes new posts in real-time.\n\n+ Lowest latency, bidirectional\n- Expensive at scale (millions of\nconnections)","textAlign":"center","verticalAlign":"middle","containerId":"shape-4","lineHeight":1.3,"autoResize":false,"customData":{"revealStep":3}},{"angle":0,"strokeColor":"#9180ac","backgroundColor":"#f4effb","fillStyle":"solid","strokeWidth":1.5,"strokeStyle":"solid","roughness":0.7,"opacity":100,"version":1,"versionNonce":1,"isDeleted":false,"groupIds":["step-4"],"frameId":null,"roundness":null,"boundElements":[{"type":"text","id":"shape-7"}],"updated":0,"link":null,"locked":false,"id":"shape-6","type":"rectangle","seed":479,"x":36,"y":505.8,"width":390,"height":293.40000000000003,"customData":{"revealStep":4}},{"angle":0,"strokeColor":"#394557","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":1.5,"strokeStyle":"solid","roughness":0.7,"opacity":100,"version":1,"versionNonce":1,"isDeleted":false,"groupIds":["step-4"],"frameId":null,"roundness":null,"boundElements":null,"updated":0,"link":null,"locked":false,"id":"shape-7","type":"text","seed":552,"x":56,"y":523.8,"width":350,"height":257.40000000000003,"fontSize":18,"fontFamily":1,"text":"Client opens persistent HTTP\nconnection.\nServer pushes new post notifications\nas they arrive.\n\n+ True push, low latency\n+ Works over HTTP (no special\nprotocol)\n- Unidirectional (server -> client only)\n- Connections consume server\nresources","originalText":"Client opens persistent HTTP\nconnection.\nServer pushes new post notifications\nas they arrive.\n\n+ True push, low latency\n+ Works over HTTP (no special\nprotocol)\n- Unidirectional (server -> client only)\n- Connections consume server\nresources","textAlign":"center","verticalAlign":"middle","containerId":"shape-6","lineHeight":1.3,"autoResize":false,"customData":{"revealStep":4}},{"angle":0,"strokeColor":"#a68a53","backgroundColor":"#fff7e6","fillStyle":"solid","strokeWidth":1.5,"strokeStyle":"solid","roughness":0.7,"opacity":100,"version":1,"versionNonce":1,"isDeleted":false,"groupIds":["step-5"],"frameId":null,"roundness":null,"boundElements":[{"type":"text","id":"shape-9"}],"updated":0,"link":null,"locked":false,"id":"shape-8","type":"rectangle","seed":625,"x":36,"y":839.2,"width":533.5678,"height":566.4,"customData":{"revealStep":5}},{"angle":0,"strokeColor":"#394557","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":1.5,"strokeStyle":"solid","roughness":0.7,"opacity":100,"version":1,"versionNonce":1,"isDeleted":false,"groupIds":["step-5"],"frameId":null,"roundness":null,"boundElements":null,"updated":0,"link":null,"locked":false,"id":"shape-9","type":"text","seed":698,"x":56,"y":857.2,"width":493.56780000000003,"height":530.4,"fontSize":17,"fontFamily":1,"text":"Real-Time Timeline Updates\n\nProblem: User has feed open. A followed user posts.\nHow does the new post appear without manual refresh?\n\nApproach 1: Polling (Simple)\n\nApproach 2: Long Polling\n\nApproach 3: Server-Sent Events (SSE)\n\nApproach 4: WebSocket (for power users)\n\nTwitter's actual approach: Hybrid\n\n- Web: polling every 30s + \"N new tweets\" banner\n- Mobile: push notification for high-priority\ncontent (mentions, viral from close friends)\n- Active sessions: SSE for timeline updates\n- Background: no connection, show stale on open\n\nOnly ~5% of users are actively viewing the feed\nat any given moment. The other 95% just need\nfresh data on next app open.","originalText":"Real-Time Timeline Updates\n\nProblem: User has feed open. A followed user posts.\nHow does the new post appear without manual refresh?\n\nApproach 1: Polling (Simple)\n\nApproach 2: Long Polling\n\nApproach 3: Server-Sent Events (SSE)\n\nApproach 4: WebSocket (for power users)\n\nTwitter's actual approach: Hybrid\n\n- Web: polling every 30s + \"N new tweets\" banner\n- Mobile: push notification for high-priority\ncontent (mentions, viral from close friends)\n- Active sessions: SSE for timeline updates\n- Background: no connection, show stale on open\n\nOnly ~5% of users are actively viewing the feed\nat any given moment. The other 95% just need\nfresh data on next app open.","textAlign":"left","verticalAlign":"middle","containerId":"shape-8","lineHeight":1.3,"autoResize":false,"customData":{"revealStep":5}}],"appState":{"viewBackgroundColor":"#fbfbf8","gridSize":null},"files":{}}