A practical lesson on queue-based work distribution, how it differs from fact-based eventing, and where background processing is the right pattern.
Work queues distribute units of work across workers. That makes them useful for background processing, smoothing bursts, and scaling asynchronous tasks. They are often confused with event-driven architecture in the broader sense because they also use brokers and asynchronous delivery. But the semantic model is different. A queue message often means “do this work,” while a domain event means “this fact happened.”
This distinction matters because the architecture should match the workload. If only one worker should process one item, a queue is often the correct model. If one fact should reach several independent consumers, a queue may be the wrong abstraction even though it is still asynchronous.
flowchart LR
A["Producer"] --> B["Work queue"]
B --> C["Worker 1"]
B --> D["Worker 2"]
B --> E["Worker 3"]
What to notice:
Queues are strong when the system needs to:
Examples include generating PDFs, resizing media, sending bulk notifications, or running expensive asynchronous enrichment jobs.
Both queues and events use asynchronous infrastructure, but they express different relationships. With a queue, the producer usually intends that the work be done by some worker. With an event, the producer records a fact that may matter to several domains. The confusion appears when teams start using queue mechanics to imitate publish-subscribe by creating one queue per interested subscriber. That works mechanically, but it often indicates that the underlying model should have been pub/sub instead.
Queues are especially useful when a user-facing request should return quickly while heavier work continues in the background. For example, a user uploads a file and gets an immediate acknowledgment, while background workers process thumbnails, virus scanning, and metadata extraction later.
This improves responsiveness, but it does not remove correctness concerns. Teams still need retry strategy, poison-message handling, and idempotent worker behavior where repeated attempts can happen.
1{
2 "taskName": "generate-monthly-statement",
3 "taskId": "task_01928",
4 "data": {
5 "accountId": "acct_882",
6 "month": "2026-02"
7 }
8}
The payload above reads like a work item, not a shared business fact. That is normal for queues.
Queues are a weaker substitute when:
In those cases, topics or streams often fit the architecture better.
A team uses a queue for order.placed and creates separate queue subscriptions for finance, analytics, and notifications because “queues are easier than pub/sub.” What should you challenge?
Challenge whether the team is using queue mechanics to simulate a one-to-many fact-distribution pattern. If several domains independently care about the same business fact, pub/sub may be the more natural model than maintaining several queue-specific arrangements around the same event.