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

Mutation, которая меняет данные, должна иметь защиту от повторного выполнения: на уровне UI, API, базы и бизнес-ключей.

Коротко: что сделать

  • Проверить, почему клиент повторяет mutation
  • Проверить двойной клик и retry клиента
  • Проверить уникальные ограничения в базе
  • Проверить наличие idempotency key
  • Проверить транзакции и обработку ошибок

Основные причины

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

  • Кнопка не блокируется после отправки
  • Apollo/клиент повторяет запрос после сетевой ошибки
  • Mutation не имеет уникального бизнес-ключа
  • Backend создает запись до проверки дубля
  • Повторный запрос приходит после timeout

Пошаговая диагностика

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

  • Сравнить два запроса mutation в Network
  • Проверить timestamps дублей в базе
  • Проверить clientMutationId или idempotency key
  • Проверить resolver и порядок операций
  • Проверить ошибки и retry policy клиента

Как исправить проблему

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

  • Добавить idempotency key для опасных mutation
  • Блокировать повторную отправку на UI
  • Добавить уникальный индекс или бизнес-ограничение
  • Выполнять создание и проверку в транзакции
  • Возвращать существующий результат при повторе ключа

Безопасный план решения

Начинайте с backend-защиты, потому что пользовательский интерфейс можно обойти. UI-блокировка улучшает UX, но не заменяет идемпотентность.

Чего не стоит делать

  • Не полагаться только на disabled-кнопку
  • Не создавать запись до проверки уникальности
  • Не повторять mutation автоматически без ключа
  • Не удалять дубли без анализа связанных данных

Что подготовить перед исправлением

  • Название mutation
  • Пример двух запросов
  • Какие дубли появляются
  • Resolver-код
  • Схема таблиц и уникальные ключи

FAQ

Что такое idempotency key?

Это уникальный ключ операции. Если тот же ключ приходит повторно, сервер возвращает прежний результат, а не выполняет действие заново.

Нужно ли добавлять ключ во все mutation?

В первую очередь в те, которые создают деньги, заказы, заявки, подписки или внешние действия.

Почему retry опасен?

Retry полезен для надежности, но без идемпотентности он может повторить бизнес-действие.

Когда стоит обратиться за помощью

Обращаться стоит, если дубли уже появились в заказах, платежах, заявках или интеграциях.

Итог

Проверьте retry, UI, resolver, транзакции и idempotency key. Если нужно защитить GraphQL mutation от дублей, пишите в Telegram @rabotator_support.