Получить доступ

Как сделать consumer идемпотентным при семантике at-least-once?

MiddleПроектирование событий
Ещё спрашивают так:
  • Как обрабатывать дубли сообщений?
Коротко

Дубли неизбежны при at-least-once, поэтому обработчик делает повтор безвредным: проверка id сообщения в таблице обработанных в той же транзакции, что и эффект, или естественно идемпотентные операции.

  • Таблица processed_messages(message_id PRIMARY KEY) + бизнес-изменение одной транзакцией
  • UPSERT, «установить статус», запись с версией вместо «прибавить»
  • Ключ дедупликации — id события от издателя, а не offset

А ещё Внешние эффекты (письмо, платёж) — ключ идемпотентности у внешнего API

Так подсказку видит пользователь sotto на живом собеседовании — за пару секунд, пока вы думаете вслух.

Подробно

Почему нужно: сообщение может прийти повторно после сбоя потребителя, ребаланса, повтора продюсера. «Прибавить 100 рублей» дважды — уже ошибка.

Способы:

  • дедупликация по id — каждое событие несёт уникальный event_id. Обработчик в одной транзакции вставляет id в таблицу обработанных (уникальный ключ) и делает изменение. Повтор упадёт на уникальности — пропускаем. Записи хранят ограниченное время;
  • естественная идемпотентность — операции, повтор которых ничего не меняет: UPSERT по ключу, «установить статус оплачен», «записать последнее значение»;
  • версии — применять событие, только если его версия больше сохранённой для агрегата (заодно защищает от перестановок);
  • внешние вызовы — передавать ключ идемпотентности во внешний API (платёжный провайдер не спишет дважды).

Важная деталь: проверка и эффект — атомарно. «Проверить в Redis, потом записать в базу» — гонка и окно для дубля при падении между шагами.

Пример

BEGIN;
INSERT INTO processed_events(event_id) VALUES ($1);   -- дубль упадёт здесь
UPDATE accounts SET balance = balance + $2 WHERE id = $3;
COMMIT;

Что хотят услышать

  • Почему дубли неизбежны.
  • Дедупликация по id в одной транзакции с эффектом.
  • Естественно идемпотентные операции и версии.
  • Внешние эффекты с ключом идемпотентности.

Частые ошибки

  • Проверять дубликат и применять эффект в разных хранилищах без атомарности.
  • Дедуплицировать по offset.

Что спросят дальше

  • Что такое inbox/outbox паттерн?
  • Как выбрать окно дедупликации?

Разбор темы

Связанные вопросы

Закрытая бета

Подсказки на собеседовании — в реальном времени

sotto слышит вопрос интервьюера и показывает короткий ответ и план, как в блоке «Коротко». Оставьте контакт — пришлём доступ и промокод.

  • Промокод на 2 часа — сверх пробных 30 минут
  • Программа для Windows — скачать сразу, войти — через Яндекс ID или VK ID
  • Прямая связь с разработчиком: что улучшить — сделаем