Повторный webhook не должен создавать второй платёж, заказ или задачу
Смотрим в тело запроса: если провайдер шлёт один и тот же event дважды, ваш хендлер обязан отвечать одинаково и не плодить побочные эффекты. Идемпотентность — это не роскошь, а база: одинаковый запрос → один результат в хранилище, даже если ретрай прилетел через секунду или через час.
Рабочая схема простая: берём уникальный ключ события и пишем его в таблицу или кеш до обработки. Пример: provider:event_id или хеш от user_id + action + payload. Если ключ уже есть — возвращаем 200 и выходим. Если нет — создаём запись, кладём задачу в очередь, а потом уже меняем состояние домена. Ретрай-политика решает всё: лучше повторно прочитать из очереди, чем дважды списать деньги.
Не путайте идемпотентность с «проверили в памяти». После рестарта памяти нет, а дубликаты есть. Нужен внешний стор с уникальным индексом:
CREATE UNIQUE INDEX uniq_evt ON processed_events(provider, event_id);
При гонке двух одинаковых запросов победит один, второй получит конфликт и тихо завершится. Ловим 5xx на ровном месте только там, где реально сломалась инфраструктура, а не бизнес-логика.
Если полезная нагрузка не даёт стабильного event_id, прокидываем стейт через метаданные сами: сохраняем checksum, timestamp, source, и отдельно фиксируем уже применённые переходы. Тогда повторный запрос не «перепридумывает» заказ, а просто подтверждает уже выполненную операцию.
Итог: сначала дедупликация, потом side effects, потом ответ. Всё остальное — приглашение к дублям, ручной сверке и ночному дебагу.
Автоматизация на вебхуках
@webhook_automation_hub_arb
Повторный webhook не должен создавать второй платёж, заказ или задачу
Этот пост опубликован в Telegram-канале Автоматизация на вебхуках. Подписаться можно по ссылке: @webhook_automation_hub_arb.