Если 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.