Lesson 5 of 18
22. Message Queues

22.4 How do acks and visibility timeouts work?

3 min read+10 XP

Reliability

At the bank: When a clerk calls your token, it's taken off the board so no other clerk calls it. If the clerk goes on a break and never finishes, after a while the manager puts the token back on the board for someone else.

In the system: When a consumer receives a message, the broker doesn't delete it; it hides it from other consumers:

  1. Receive: the message becomes invisible (in flight) for a visibility timeout, 30 seconds by default in SQS (up to 12 hours).
  2. Ack (delete) within the timeout: the message is gone for good.
  3. No ack in time (the worker crashed or is too slow): the message becomes visible again and another consumer gets it.

visible, hidden while being worked on, deleted on ack; back to visible if no ack; DLQ after several failures.

Figure: an unacknowledged message always comes back, which is what makes at-least-once work.

In the chapter's code, a message received at second 0 is invisible at second 10, and reappears at second 31 when the worker never acked it.

RabbitMQ does the same with unacked messages: if the consumer's connection closes, they're requeued. Kafka works differently: the consumer commits an offset ("I've processed up to message 4,812"); after a crash, the next consumer restarts from the last committed offset.

Getting the timeout right:

  • Longer than the slowest normal job. If processing can take 45 seconds, a 30-second timeout guarantees duplicates.
  • Extend it while working for long jobs (SQS lets you change a message's visibility; many libraries send heartbeats).
  • Not too long, or a crashed worker's messages sit hidden for ages before retrying.
  • Prefetch limits (RabbitMQ prefetch, SQS batch size): don't let one worker grab 500 messages it can't finish in time.

Memory code: "Taken off the board while you work; put back if you don't finish."