Every messaging system has to answer one question: if something fails halfway, does the message get processed zero times, once, or twice? There are three possible promises, and the one everyone wants, "exactly once", is also the one most often misunderstood.
Module 7 met this for background jobs, and Module 12 showed how idempotency keys make a retried request safe. This lesson looks at the same problem through a message broker, where there are failures at two ends: the producer sending, and the consumer processing.
Where messages get lost or doubled
A message goes through three hops, and each can fail:
Producer to broker. The producer sends a message and waits for an acknowledgement. The network times out. Did the broker store it? The producer can't tell (Module 12: a timeout tells you nothing). If it retries, the message might be stored twice. If it doesn't, it might be lost.
Inside the broker. The leader stores the message and acknowledges, then dies before followers copy it. A follower becomes leader without the message. That's what acks=all and min.insync.replicas protect against, from the Kafka lesson.
Broker to consumer. The consumer reads a message, processes it (sends a push, writes to a database) and commits its offset. It can crash between processing and committing, or between committing and processing.