Webhook не является гарантией единственной и мгновенной доставки: запрос может потеряться, получить timeout или повториться. Поэтому синхронизация должна уметь принять повтор и периодически сверять итоговое состояние через API.
Найдите событие у отправителя, проверьте журнал входящих запросов и выполните безопасную повторную обработку по event_id. Затем добавьте reconciliation, чтобы единичный потерянный webhook не оставлял данные навсегда разными.
Коротко: что сделать
- Проверить event_id и время у отправителя
- Проверить HTTP-логи и код ответа
- Проверить подпись и timestamp
- Проверить очередь и dead-letter
- Сравнить итоговый объект через API источника
Почему возникает проблема
Событие может дойти до прокси, но не до приложения, либо приложение может сохранить данные и вернуть timeout. Оба случая требуют журналирования и идемпотентности.
- Endpoint был недоступен во время отправки
- Прокси ограничил body или timeout
- Проверка подписи использует измененное тело
- Приложение вернуло 500 после частичной записи
- Retry отключен или слишком короткий
- Событие попало в DLQ без оповещения
Пошаговая диагностика
Проверку лучше проводить на одном воспроизводимом примере и фиксировать результат каждого шага. Так можно быстро отделить первопричину от побочных ошибок и не менять несколько компонентов одновременно.
- Проследить event_id через proxy, app и queue logs
- Сверить raw body до JSON-разбора
- Проверить правила retry отправителя
- Проверить обработку неуспешных HTTP-кодов
- Повторить событие в тестовой среде
- Сравнить локальную запись с API источника
Как исправить
Endpoint должен быстро подтвердить прием после надежной записи события, а бизнес-обработку выполнять асинхронно и идемпотентно.
- Сохранять raw event и event_id до обработки
- Проверять подпись по исходному телу
- Отвечать 2xx только после надежного приема
- Обрабатывать событие через очередь с retries и DLQ
- Добавить уникальный индекс event_id
- Запустить периодическую reconciliation по измененным объектам
Как проверить результат
- Отправить одно событие повторно
- Смоделировать timeout после приема
- Смоделировать недоступность worker
- Проверить оповещение по DLQ
- Убедиться, что сверка восстанавливает пропущенное состояние
Как не допустить повторения
Надежная интеграция предполагает, что webhook может быть потерян, задержан или повторен.
- Хранить event log с ограниченным сроком
- Мониторить задержку и процент ошибок
- Иметь безопасную кнопку replay
- Проводить регулярную сверку состояния
Чего не стоит делать
- Не выполнять тяжелую обработку до HTTP-ответа
- Не принимать webhook без проверки подписи
- Не считать порядок доставки гарантированным
- Не делать ручной replay без идемпотентности
Что подготовить для диагностики
- Event ID и время
- HTTP-коды отправки
- Raw body и заголовки без секретов
- Логи endpoint и worker
- Описание API для сверки
Частые вопросы
Можно ли гарантировать, что webhook не потеряется?
Абсолютно — нет. Надежность достигается retries, журналом и сверкой состояния.
Когда возвращать 200?
После проверки запроса и надежной фиксации события, но до длительной бизнес-обработки.
Зачем event_id?
Он позволяет распознать повтор и безопасно переиграть событие без двойного результата.
Когда стоит обратиться за помощью
Обратитесь за помощью, если события влияют на оплату, статусы заказов или доступ клиентов и нужно восстановить пропуски без создания дублей.
Итог
Webhook нужно дополнять журналом, очередью, идемпотентностью и сверкой через API. Построить или восстановить такую интеграцию можно через @rabotator_support.