Блог
Цветные бумажные конверты летят к открытому почтовому ящику.

31 августа 2026 г.4 минуты чтенияАдминистратор

Вебхук пришёл дважды. Почему заказ должен исполниться один раз

Практическая схема приёма платёжных событий: проверка подлинности, защита от повторов, согласование статусов и восстановление пропущенных операций.

HTTP 200 уже отправлен, а начисления в балансе нет. В журнале написано «успех», клиент ждёт товар, провайдер больше не обязан немедленно повторять доставку. Такая поломка появляется на стыке двух событий: сообщение приняли, но бизнес-действие не довели до конца. Разбирать вебхуки полезнее именно с этой границы, а не с написания обработчика на десять строк.

Сначала определите, какой системе доверять

У платёжной интеграции несколько разных вопросов. Провайдер сообщает состояние своей операции. Внутренний реестр показывает, какие действия уже выполнила платформа. Расчётный отчёт помогает проверить фактическое движение денег. Назначьте источник истины каждому вопросу: статус платежа проверяется по предусмотренному провайдером механизму, отгрузка подтверждается внутренней записью, поступление в расчёт проверяется сверкой. Даже корректное уведомление об оплате не следует превращать в универсальное доказательство всех трёх событий.

Для каждого адаптера составьте короткий контракт: какие идентификаторы стабильны, какие события могут повторяться, где доступно актуальное состояние и какие изменения считаются допустимыми. Например, Stripe допускает повторные доставки и не гарантирует порядок событий. Одной сортировки по времени недостаточно для доказательства допустимости перехода состояния. Этот нюанс важнее красивой общей схемы, одинаковой для любых провайдеров.

Разделите приём события и выполнение действия

Предлагаемая схема начинается с проверки подлинности по правилам конкретного API. Затем событие получает запись во входящем журнале, а бизнес-обработка выполняется отдельно. Подтверждение приёма отправляйте в предусмотренный контрактом срок, после надёжного сохранения сообщения. Если запись не удалась, система не должна притворяться, что событие уже принято. Длительную отгрузку, письмо покупателю или обновление отчёта не стоит включать в этот короткий путь.

Проверка подлинности тоже зависит от поставщика. PayPal описывает проверку подписи уведомления; при самостоятельной проверке важны исходные байты тела. Поэтому заранее проверьте, не меняет ли промежуточный обработчик приложения исходные данные до проверки. Не переносите требования одного сервиса в другой без чтения соответствующей документации.

Во входящем журнале полезно хранить провайдера, контекст аккаунта, идентификатор события, идентификатор операции, время получения, результат проверки и состояние обработки. Полное тело сохраняйте только при обоснованной необходимости, с ограничением доступа и сроком хранения. Поддержке обычно нужны ссылки и статусы, а не копия персональных данных из каждого сообщения.

Повтор доставки и повтор бизнес-действия различаются

Проверка идентификатора события остановит повтор той же доставки. Дополнительно защитите само действие: для пары «операция оплаты + начисление» должна существовать только одна разрешённая запись выполнения. Это отдельный уровень защиты, потому что разные сообщения могут описывать один бизнес-результат. Запись о выполненном действии и изменение внутреннего баланса проектируйте как согласованную операцию; иначе сбой между ними оставит возможность повторного начисления.

Не выбирайте ключ дедупликации наугад. Adyen описывает повторы с одинаковыми eventCode и pspReference, хотя другие поля могут отличаться. Значит, универсальный хеш всего JSON не заменяет правила конкретного формата. При этом слишком широкий ключ способен скрыть законное последующее событие, например отдельный частичный возврат.

Разберите один платёж до конца

В условном примере заказ M-418 стоит 72 евро. Событие подтверждённой оплаты сохраняется первым. Рабочий процесс находит заказ, сверяет сумму, валюту и аккаунт, обновляет платёж и создаёт одно задание на отгрузку. Позднее уведомление об обработке остаётся в истории, но не возвращает заказ назад. Второе подтверждение оплаты не создаёт ещё одну отгрузку. Событие возврата обрабатывается по собственному идентификатору и правилам, а не отбрасывается потому, что заказ уже оплачен.

Если сообщения противоречат друг другу, поместите операцию на разбор и запросите актуальные данные разрешённым способом. Для метода без подходящего онлайн-запроса используйте предусмотренные отчёты и эскалацию провайдеру. Отсутствие нового вебхука само по себе не доказывает отказ.

Красная очередь должна иметь выход

Отдельная очередь ошибок полезна, пока из неё можно безопасно вернуть событие в работу. В предлагаемом процессе запись содержит причину остановки: неизвестный заказ, конфликт суммы, неподдерживаемый тип или техническая ошибка. Первые три причины требуют решения, последняя может разрешиться повтором. Одна кнопка «переиграть всё» стирает эту разницу и превращает восстановление в новый инцидент.

Перед повторной обработкой покажите оператору, что уже выполнено: начисление, отгрузка, возврат, уведомление клиенту. Повторять нужно недостающий разрешённый шаг. Если заново запустить весь бизнес-сценарий после исправления парсера, идемпотентный приём события ещё не гарантирует идемпотентную отправку письма или создание доставки. Тестируйте побочные действия отдельно, в том числе после обновления кода.

Возраст важнее красивого процента

Условная очередь содержит 900 свежих событий и одно сообщение, застрявшее со вчерашнего дня. Среднее время обработки может выглядеть прилично, пока один покупатель остаётся без результата. Следите за возрастом самого старого необработанного события по типам операций и за числом событий без владельца. Для возвратов, выдачи товара и информационных уведомлений допустимые задержки могут различаться.

Для проверки восстановления выберите конкретное событие и проведите его от первичного приёма до финансового эффекта. Запишите не только результат, но и версию обработчика. Когда формат данных изменится, станет понятно, какие старые события можно воспроизвести новым кодом, а каким потребуется совместимый разбор. Не храните полный payload бессрочно ради гипотетической отладки: достаточно обоснованного набора сведений и утверждённого срока.

Выберите одно вчерашнее событие из очереди ошибок. Если сотрудник может безопасно завершить именно недостающее действие и показать, почему остальные не повторятся, путь восстановления действительно существует. Если он вынужден вручную менять статус заказа, обработчик вебхуков ещё оставляет работу системе догадок.

Источники

  1. 1.docs.stripe.com/webhooks
  2. 2.docs.adyen.com/development-resources/webhooks/handle-webhook-events
  3. 3.developer.paypal.com/api/rest/webhooks/rest

Комментарии · 0

Комментариев пока нет — будьте первым.

Войти · войдите, чтобы оставить комментарий.