Back to TutorialsSystem Design · Chapter 8

Message Queues & Asynchronous Processing

Not every operation needs to happen synchronously in the request path. Message queues decouple producers from consumers and smooth out traffic spikes.

Why Decouple with a Queue

If sending a confirmation email is part of your signup request, a slow email provider slows down every signup. Publishing a "user signed up" event to a queue lets the signup request return immediately, while a separate worker processes the email asynchronously.

Common Patterns

Point-to-point queues (SQS, RabbitMQ) deliver each message to exactly one consumer — good for task distribution. Pub/sub systems (Kafka, SNS) broadcast events to multiple independent subscribers — good for fan-out, like updating a search index and a cache from the same event.

It's worth being able to explain why you'd pick one over the other in a specific scenario: a payment processing job that must run exactly once per order fits point-to-point cleanly, while a single "referral status changed" event that needs to update analytics, notify the candidate, and update a dashboard simultaneously fits pub/sub far better.

Trade-offs to Mention

Async processing adds eventual consistency and operational complexity (dead-letter queues, retry logic, ordering guarantees). Bring this up proactively — it shows you understand the cost, not just the benefit.

Handling Failures Gracefully

Messages can fail to process. A retry policy with exponential backoff handles transient failures, while a dead-letter queue captures messages that fail repeatedly so they can be inspected rather than silently dropped or retried forever.

When Not to Use a Queue

Not everything should be async. If a user needs an immediate, synchronous confirmation that an action succeeded — like a payment — that path usually needs to stay in the request-response cycle, with async work reserved for side effects that don't block the user.

Idempotency Matters More Than People Expect

Most queues offer "at-least-once" delivery, meaning a consumer might process the same message twice — during a retry, or after a crash and redelivery. Designing consumers to be idempotent (processing the same message twice has the same effect as once, usually via a dedup ID) is one of the most commonly forgotten details in async designs, and interviewers often probe for it directly.

Ready to put this into practice?

Upload your resume and get matched with a verified referrer today.

Get Started