Serverless-платформы и очереди часто используют модель at-least-once delivery: событие может прийти больше одного раза. Если функция не идемпотентна, она создает дубли заказов, писем, платежей или записей.
Сначала проверьте, действительно ли событие одно и то же: event id, payload, timestamp, retry reason и логи запуска. Потом делайте обработку устойчивой к повтору.
Коротко: что делать
- Сравнить event id у двух запусков
- Проверить retry policy и timeout функции
- Проверить, не отправляет ли источник событие дважды
- Найти побочные эффекты: insert, email, payment, webhook
- Добавить идемпотентный ключ обработки
Основные причины
У этой проблемы редко бывает одна универсальная причина. Обычно нужно проверить связку настроек, данных, кода и внешних сервисов, а потом уже выбирать способ исправления.
- Платформа повторяет событие после timeout или ошибки
- Источник отправляет webhook повторно без подтверждения
- Функция выполняется дольше лимита и получает retry
- Нет проверки уже обработанного event id
- Один trigger подписан дважды или на несколько источников
Пошаговая диагностика
Диагностику лучше вести от конкретного примера: один пользователь, один запрос, один документ, одно событие или один экран. Так проще увидеть точку, где система начинает вести себя неправильно.
- Собрать логи двух запусков рядом
- Проверить correlation id/event id
- Проверить код ответа функции источнику события
- Проверить настройки retry и dead-letter queue
- Проверить список triggers и подписок
Как исправить проблему
Исправление должно закрывать корневую причину, а не только внешний симптом. Если проблема связана с доступами, платежами, данными или безопасностью, сначала стоит сделать резервную копию и проверить правку на тестовом сценарии.
- Добавить таблицу обработанных event id или idempotency key
- Делать запись результата транзакционно
- Отвечать источнику webhook только после безопасного приема события
- Уменьшить риск timeout или вынести долгую работу в очередь
- Настроить retry, DLQ и мониторинг повторов
Безопасный план решения
Считайте повтор события нормальным сценарием, а не исключением. Код должен безопасно переживать повторный запуск без дублей.
Чего не стоит делать
- Не отключать retry без понимания последствий
- Не делать платежи, письма и insert без идемпотентности
- Не считать timestamp уникальным ключом
- Не игнорировать timeout как причину повторов
Что подготовить перед исправлением
- Платформа serverless
- Логи двух запусков
- Payload события без секретов
- Что именно дублируется после повтора
FAQ
Это баг serverless-платформы?
Обычно нет. Повторная доставка часто является нормальной гарантией надежности.
Какой ключ использовать для идемпотентности?
Лучше event id от источника, id заказа, id платежа или собственный стабильный hash payload.
Нужно ли отключать retries?
Редко. Лучше сделать обработчик безопасным и отправлять неуспешные события в DLQ.
Когда стоит обратиться за помощью
Помощь нужна, если повторы создают финансовые операции, письма клиентам, заявки, документы или записи в CRM.
Итог
Начните с event id и retry policy. Если нужно сделать serverless-функцию идемпотентной и убрать дубли, можно написать в Telegram @rabotator_support.