Сахан Серасингхе 12 июля разобрал класс потерь в событийных системах, где сообщение пропадает без исключения, без строчки в логе и без попадания в очередь недоставленных. Он называет это разрывом подтверждения: приём запроса подтверждён, а работа так и не началась.
Доставка at-least-once держится на повторах и идемпотентных потребителях, и оба механизма опираются на одно допущение: если обработка не удалась, потребитель об этом узнает. Но ответ 202 Accepted значит «запрос принят», а не «работа выполнена», и даже 204 No Content бывает двусмысленным. Коммит offset при этом означает куда более сильное: все сообщения до N обработаны полностью и повторять их нельзя.
🔘 типичный сценарий: потребитель отправляет задачу, получает 204, коммитит offset, а управляющий слой через миллисекунды отклоняет её из-за квоты, admission control или переполнения внутренней очереди;
🔘 проверка только на
err != nil опасна, потому что самый разрушительный исход выглядит как nil;🔘 граница может быть любой асинхронной: брокер очередей, workflow engine, фоновый обработчик, HTTP-диспетчер;
🔘 повторы, идемпотентность и транзакция брокера тут не спасают, раз подтверждается только приём задачи;
🔘 надёжнее подтверждать запуск отдельно: чтение после записи или опрос по correlation ID, а явный отказ считать ошибкой;
🔘 повторы ограничивают бюджетом, а после его исчерпания шлют алерт или отправляют сообщение в очередь недоставленных.
Автор отдельно оговаривает обратный риск. Ошибка самой проверки состояния не должна автоматически порождать новую отправку, иначе вместо потерянного сообщения появится дубликат, и вся идемпотентность на стороне обработчика уедет в мусор.
Полная статья: https://sahansera.dev/the-acknowledgment-gap/
Сохранять тем, кто отлаживает пропажу заказов или платежей, которые в логах отправителя выглядят успешно обработанными.
@prog_stuff