// Communication & Integration · 05
Message Queue
Drop the work off and move on. One consumer picks up each message.
How it fits together
- Orders API creates Invoice queue (1 send)
- Invoice queue uses / calls Worker 1 (2 receive)
- Invoice queue uses / calls Worker 2 (2 receive)
- Invoice queue uses / calls Worker 3 (2 receive)
- Worker 3 fails / error path Dead-letter queue (after 5 tries)
Spot it
- Requests time out waiting on slow work
- Traffic spikes overwhelm a downstream service
- Work is lost when a worker crashes mid-task
It costs
The caller no longer gets an immediate result, and the broker is one more thing to run.
In code
public sealed class InvoiceWorker(IQueueReceiver queue, IInvoiceStorage storage){ public async Task RunAsync(CancellationToken ct) { await foreach (var message in queue.ReceiveAsync(ct)) { try { var command = message.Body.Deserialize<GenerateInvoice>(); var pdf = await InvoicePdf.RenderAsync(command, ct); await storage.SaveAsync(command.InvoiceId, pdf, ct); await message.CompleteAsync(ct); } catch (Exception) when (message.DeliveryCount >= 5) { await message.DeadLetterAsync(ct); } catch (Exception) { await message.AbandonAsync(ct); } } }}Go deeperThe full explanation and what to ask for · 1 min readExpandCollapse
A queue decouples sender and receiver in time: the producer only needs the broker to be up, and consumers pull at their own pace. Several consumers on one queue compete for messages, so adding workers raises throughput and spikes turn into queue depth instead of errors.
The classic mistake is acknowledging a message before the work is done, which loses it on a crash, or assuming exactly-once delivery. Brokers redeliver when a lock or visibility timeout expires, so handlers must be idempotent and the timeout longer than the work.
A queue means one logical receiver per message, which suits commands. When several parties should each react to the same fact, use publish/subscribe. Pair queues with an outbox for reliable sending and a dead-letter queue for poison messages.
Ask for it
- competing consumers
- lock / visibility timeout
- complete / ack
- at-least-once delivery
- queue depth
- sessions (FIFO)
Move PDF generation off the request: the API sends a GenerateInvoice message to a queue (Kafka, RabbitMQ, SQS, Azure Service Bus) and returns 202 with a status URL; a worker takes messages under a 60s lock, completes only after the file is stored, and dead-letters after 5 deliveries.