Описать проблему ↗

Дубли и данные

Повторный webhook создаёт два платежа: идемпотентность

Платёжное уведомление пришло повторно и создало лишнюю операцию. Разберём идемпотентность: как узнать повтор события и не выполнить действие дважды.

Редакция «починимсайт» · Обновлено · 3 мин. чтения

Что происходит и с чего начать

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

Что можно проверить самостоятельно

  1. Сохраните идентификаторы двух событий и связанной операции, время и созданные записи. Отдельно проверьте, было ли повторное списание у провайдера или только дубль учёта на сайте.
  2. Проследите, какие действия выполняются после оплаты: письмо, резерв, выдача доступа, документ. Некоторые из них могли повториться, даже если сама запись платежа одна.
  3. Уточните, повторяется ли проблема после тайм-аутов или параллельной обработки. Не удаляйте отметки завершённых событий ради повторного теста на настоящих оплаченных заказах.

Как понять результаты проверки

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

Что проверяет разработчик

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

  1. Сравните идентификаторы событий и платежей у дублей. Один платёж может иметь несколько разных событий, поэтому ключ нужно выбирать по смыслу операции.
  2. Проверьте параллельную обработку: два запроса могут одновременно не найти запись и оба создать её. Обычной проверки SELECT перед INSERT недостаточно.
  3. Проследите побочные действия: смену статуса, письмо, резерв и выдачу доступа. Защита только таблицы платежей не исключает повторов остальных эффектов.

На что обратить внимание

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

Как исправляют причину

Используйте устойчивый ключ операции, ограничение уникальности и согласованную транзакцию. Для внешних эффектов предусмотрите отдельное устойчивое состояние доставки. Подлинность события проверяйте до изменения данных.

Как убедиться, что проблема решена

Отправьте одинаковое событие последовательно и параллельно на тестовой системе. Результат должен соответствовать одному платежу, а повтор получать предусмотренный протоколом ответ без повторных эффектов.

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