CMD Guide
HomeSystem DesignDistributed File System

EventDriven vs Polling Architecture

The whole choice reduces to who pays to discover that state changed: in polling the consumer repeatedly asks the source "anything new?" on a timer, so cost scales with poll frequency regardless of how often data actually changes; in event-driven the source pushes a notification the instant state changes, so cost scales with the change rate. Freshness in polling is bounded by the interval; freshness in event-driven is bounded only by network delivery.

Correcting the common myth: polling is not inherently blocking

Polling only means "check on a schedule." It says nothing about threading. A blocking poll (while(true){ r = httpGet(); sleep(5s); } on a dedicated thread) is one implementation, but polling is routinely done asynchronously and non-blocking: a scheduled async job, a non-blocking HTTP client that yields its thread between requests, a browser setInterval firing fetch(), or a Kafka consumer's poll(timeout) loop on one thread serving thousands of partitions. The real, unavoidable cost of polling is not blocking — it is wasted requests (most polls return "nothing changed") and detection latency (up to one full interval). Those two are the levers you actually trade against.

The middle ground the bullet-list version skips

It is not a binary. Four points sit on a spectrum from "consumer pulls" to "producer pushes":

Event-driven internally (Kafka, RabbitMQ, an in-process event bus) is the same idea within your own system: producers emit, brokers fan out, consumers react. When you cannot trust every writer to emit an event — a legacy database, a multi-writer schema, code you do not own — the alternative source is change-data-capture (CDC): a connector tails the database's replication log (MySQL binlog, Postgres WAL) and turns every committed row change into an event. CDC buys you completeness (nothing that hits the table is missed) at the cost of coupling your event stream to the storage engine's log format and schema.

Worked example: 10,000 clients waiting for a "new message"

Assume 10,000 connected clients, and on average each receives 1 message per hour, so the real event rate is 10,000 / 3600 ≈ 2.8 messages/sec. Watch what each strategy costs to deliver those same 2.8 messages/sec.

StrategyRequests/sec to serverAvg detection latencyWasted (empty) work
Short poll, interval 5s10000 / 5 = 2000/sT/2 = 2.5s (worst 5s)≈ 1997 of 2000 polls empty → 99.9%
Short poll, interval 1s (fresher)10000 / 1 = 10000/s0.5s avgStill ≈ 99.97% empty; 5× the load for 5× freshness
Long poll, 30s hold≈ event rate + reconnects ≈ 3–350/s≈ network only (~ms)Minimal; connections mostly idle-waiting
Event-driven push (WebSocket/webhook)2.8/s (one push per real event)≈ network only (~ms)≈ 0

The punchline: short polling spends 2000 req/s to move 2.8 req/s of real signal — a 700:1 overhead — and still lags by up to 5 seconds. Halving the latency doubles the load. Push delivers the same messages at the true event rate with sub-second latency. That freshness-vs-load curve is the entire design tension, and it is why high-fan-out, low-event-rate systems (notifications, presence, dashboards) lean event-driven.

diagram
diagram

Pitfalls

When to use it / when NOT to

Reach for polling when: events are rare and non-urgent (a nightly backup checking for new files, a health check every 30s); you cannot open inbound connections or register webhooks (a client behind a firewall pulling from a third-party API); the source has no push capability; or the client set is small. Polling's gains are operational simplicity — no broker, no persistent connections, trivially stateless, works through any proxy, and dead-easy to reason about and retry.

Reach for event-driven when: you need sub-second freshness, fan-out is large, the event rate is low relative to the client count (so polling would be almost entirely wasted work), or you are decoupling microservices that should not know about each other's schedules.

Trade-off vs the named alternative. Choosing event-driven over polling buys you low latency and near-zero wasted work, but it costs: a broker or connection layer to operate, delivery guarantees you must build (retries, DLQ, idempotency), harder debugging (flow is implicit and asynchronous — no single call stack), and coupling to infrastructure availability. Polling costs you latency and wasted requests but keeps the system a boring, debuggable request/response. Long polling is the pragmatic compromise: push-like freshness with polling's plain-HTTP simplicity, at the price of held connections.

Decision rule: choose event-driven when freshness is a product requirement and fan-out is high; choose polling when events are infrequent, the client count is modest, or infrastructure/connectivity forbids push; choose long polling when you want push-like latency but must stay on stateless HTTP.

Takeaways

Reconnect catch-up: sequence IDs plus stream buffering

Push systems need a memory outside the socket. Give every event for a client or topic a monotonic sequence ID, and have the client persist the largest sequence it has fully processed. That sequence is the client's read position: "I am complete through seq=104." The server can then replay exactly events with seq > 104, avoiding both gaps and unnecessary full refreshes.

The server-side buffer can be a short-retention log such as Redis Streams, Kafka, or an outbox table keyed by user/topic. With Redis Streams, events are appended with XADD stream:user:42 * seq 105 payload ...; reconnect reads use XRANGE or XREAD from the last seen ID, followed by live tailing.

For SSE, the browser already exposes the handshake: send each event with id: 105; after disconnect, EventSource reconnects with the Last-Event-ID header. For WebSockets, put the same cursor in the first message or query parameter, e.g. wss://.../feed?last_seq=104. The server first pushes the catch-up range, then switches the connection to live events. If last_seq is older than retention, fail loudly and force a snapshot resync rather than pretending the gap did not happen.

The two systems even fail on opposite dashboards. Polling's fingerprint is periodic QPS spikes aligned to poll boundaries (worst right after an outage, when every client's backoff expires together — the reconnect storm), so you watch request rate for a sawtooth and alert on jitter loss. Event-driven's fingerprint is a backlog of undelivered events / consumer lag and a rising DLQ depth — a broken subscriber goes silent rather than loud, so you alert on delivery lag and DLQ arrival, not on request rate.


Sources: Martin Kleppmann, Designing Data-Intensive Applications (Ch. 11, streams & change events); Mozilla MDN Web Docs on long polling, Server-Sent Events, and WebSockets; the Apache Kafka consumer poll() documentation; and webhook delivery guidance from the Stripe and GitHub API docs. Re-authored/Deepened for this guide.

🤖 Don't fully get this? Learn it with Claude

Stuck on EventDriven vs Polling Architecture? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.

🎨 Explain it visually

Build the mental picture, not memorization.

I just read a lesson on **EventDriven vs Polling Architecture** (System Design) and want to truly understand it. Explain EventDriven vs Polling Architecture from first principles using ONE vivid real-world analogy and a visual mental model — draw it as ASCII art or a clear step-by-step diagram — with a concrete example using real numbers. Then ask me one question to check I got the mental picture, and wait for my reply. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🤔 Walk me through it (interactive)

Socratic — adapts to where you're stuck.

Teach me **EventDriven vs Polling Architecture** interactively. Ask me ONE guiding question at a time, wait for my answer, and adapt to my confusion — build the idea with me step by step instead of explaining it all at once. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧪 Quiz me & fix my gaps

Active recall exposes what you missed.

Quiz me on **EventDriven vs Polling Architecture** with 5 questions, easy to tricky, ONE at a time. Tell me if each answer is right; at the end, explain clearly what I got wrong and why. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧠 Make it stick

Intuition + hook + flashcards for long-term memory.

Help me remember **EventDriven vs Polling Architecture** for the long term: give the one-sentence intuition, a memorable hook/mnemonic, a tiny worked example, and 3 active-recall flashcards (Q -> A). If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.

📝 My notes