Build the mental model
Some work triggered by a user request — sending a confirmation email, resizing an uploaded image, rebuilding a search index entry — doesn't need to finish before the user sees a response, but a naive implementation does it synchronously inline, making the user wait for the slowest step even though they don't care about its result. A message queue decouples this: the web server (producer) does only the fast, essential work, then pushes a small message describing the task onto a queue and immediately returns a response to the user; a separate worker process (consumer) pulls messages off the queue whenever it's free and performs the slow work independently. This decouples producer and consumer in time and identity — neither needs the other online simultaneously, and you can scale workers independently of web servers. The catch is delivery guarantees: most real queues promise at-least-once delivery, meaning a message might be delivered and processed more than once (e.g., after a worker crash mid-task and retry), so consumers must be idempotent — processing the same message twice must produce the same end result as processing it once, not duplicate side effects.
Connect it to a real scenario
When a learner completes a course on the Tutorial Platform, several things should happen: send a congratulations email, generate a PDF certificate, update the leaderboard, and reindex the learner's profile for search — none of which the learner needs to wait for. Doing all of this synchronously would make 'mark course complete' feel sluggish and fail entirely if, say, the email service is briefly down. Instead, the web server enqueues a single 'course-completed' message and responds instantly; separate workers consume it and handle each downstream task, retrying independently on failure — a slow PDF generator doesn't block the leaderboard update, and a transient email outage doesn't block certificate generation.
Try the working example
REQUEST FLOW
User --> [Web Server / Producer]
|
| 1. enqueue "course-completed" message
v
+----------+
| QUEUE |
+----------+
|
| 2. respond to user IMMEDIATELY (doesn't wait)
v
User sees "Course complete!" (fast)
meanwhile, asynchronously:
|
+--------+--------+--------+
v v v v
Worker1 Worker2 Worker3 Worker4
(email) (PDF cert)(leader- (search
board) reindex)
If Worker1 crashes mid-task -> message redelivered -> retried
(consumer must be idempotent: processing twice = same end result)The diagram shows the user gets an instant response without waiting for background tasks, while workers process the slow work independently and asynchronously.5-minute try-it
When a learner submits a quiz on the Tutorial Platform, distinguish score calculation (the user needs to wait) from logging an analytics event (they don't) — decide which should stay synchronous and which should go through the queue asynchronously.
One important caution
Failing to make the worker consumer idempotent means a redelivered message (due to at-least-once delivery) can cause duplicate side effects, like sending the congratulations email twice.
Moving genuinely critical work (like finalizing a payment) to async processing without robust error handling/monitoring means the user sees 'success' while backend processing silently fails with nobody noticing.
Wikipedia — Message queue — System Design