Lesson 3.5.1 showed that “at least once” means: sometimes twice. In this lesson you make sure the receiver can take that. You start with a lab in which a repeated message creates two tenders and two emails, and you fix it with a unique key, an inbox and an outbox. Then you learn what Service Bus duplicate detection does and what it doesn't, and build both into the Kladde. At the end, the bug from lesson 3.5.3, in which an event could get lost, is fixed too.
A receiver is called idempotent if it makes no difference to the result whether it processes a message once or several times. The upsert from K2 is idempotent: The same notice twice gives one row. Sending an email is not: Sent twice means twice in the inbox.
Where duplicates come from
A message arrives a second time when the broker isn't sure that it has been processed. That happens more often than you'd think:
- The lock is lost. The work takes longer than lock duration and renewal together, or the connection briefly drops. A second worker gets the same message while the first is still working.
- The receiver crashes after the work. The data is saved, but
CompleteMessageAsyncnever arrived. - The response to the completion gets lost. The broker has completed the message, the receiver gets a timeout, takes the message for not completed and tries again with the next delivery.
- The sender sends twice. It gets a timeout while sending even though the message arrived, and sends it once more. An outbox that sends its last row again after a crash does the same.
- The source delivers twice. Event Grid delivers an event again if it gets no response. The nightly fetch runs a second time after a restart.
A better broker helps against none of these. Help comes only from the receiver itself.