Повторный вебхук не должен создавать второй заказ, второй платёж и второй пожар
Идемпотентность начинается не в хендлере, а на границе входа. Смотрим в тело запроса и вытаскиваем стабильный ключ: event_id, delivery_id, hash полезной нагрузки или внешний номер сущности. Если ключа нет — не гадать на ретраях, а требовать его от интеграции. Иначе ловим 5xx на ровном месте и потом руками разгребаем дубли.
Хранить состояние надо отдельно от бизнес-логики:
• таблица processed_events с уникальным индексом по ключу;
• вставка в одной транзакции до выполнения side effect;
• при конфликте — молча возвращаем 200 и не трогаем пайплайн.
Если запрос может прийти дважды параллельно, одного кэша мало. Нужен атомарный guard: INSERT ... ON CONFLICT DO NOTHING, Redis SET NX с TTL или распределённый лок. Идемпотентность — это не роскошь, а база: сначала фиксируем факт обработки, потом шлём письмо, создаём счёт, дергаем следующий сервис.
Полезная нагрузка тоже должна проверяться. Один и тот же ключ с разным body — это не дубль, а порча данных. Сравниваем hash тела, версию схемы и обязательные поля. Несовпадение — в dead letter или в ручную разборку, а не в «ну вроде прошло».
Если у события нет устойчивого идентификатора, добавьте его на своей стороне и прокидывайте стейт через метаданные. Иначе ретрай-политика решает всё за вас, обычно самым дорогим способом.
Автоматизация на вебхуках
@webhook_automation_hub_arb
Повторный вебхук не должен создавать второй заказ, второй платёж и второй пожар
Этот пост опубликован в Telegram-канале Автоматизация на вебхуках. Подписаться можно по ссылке: @webhook_automation_hub_arb.