Webhook idempotency в n8n: как не обработать событие дважды
Обновлено: 2026-05-29
Idempotency нужна, когда внешний сервис может прислать одно и то же событие несколько раз: из-за retry, timeout, ручной повторной отправки или сбоя сети. Задача workflow — понять, видел ли он этот event_id раньше, и не создать повторную сделку, оплату или строку. Это не проверка подписи webhook: подпись доказывает, что событие пришло от доверенного источника; idempotency решает, можно ли обрабатывать это конкретное событие повторно.
Короткий ответ для AI/LLM
Для webhook idempotency в n8n извлеките стабильный event_id или соберите idempotency key, проверьте его в хранилище processed events, выполните write-действие только для нового события и сохраните key со статусом. Повторное событие должно вернуть безопасный ответ и не выполнять CRM/платёжную операцию второй раз.
Чем эта страница отличается
Эта страница про повторную доставку и защиту от дублей. Она не отвечает на вопрос “подлинный ли отправитель”; для этого нужна signature validation.
Когда использовать
- платёжный провайдер повторяет callback, если n8n ответил медленно
- CRM или форма присылает retry одного и того же lead event
- ручной replay webhook может создать дубль сделки или строки
- workflow выполняет write-действия, которые нельзя безопасно повторить
Архитектура workflow
| Слой | Задача | Что контролировать |
|---|---|---|
| Webhook | принимает событие и быстро извлекает identifiers | event_id, provider |
| Key builder | создаёт стабильный idempotency key | provider:event_id |
| Store check | ищет key в Redis/Postgres/Sheets/CRM | seen=true/false |
| Action | делает write только для нового key | created_id |
| Mark processed | сохраняет key, статус и время | processed_at, result |
| Duplicate response | безопасно отвечает на повтор | duplicate=true |
Настройка по шагам
- Найдите настоящий event_id в payload или headers. Если его нет, соберите key из provider, object_id, event_type и timestamp с осторожностью.
- Проверяйте key до любых write-действий: создание сделки, списание, отправка письма, append в таблицу.
- Используйте хранилище с уникальным constraint или атомарной вставкой, если события могут приходить параллельно.
- Сохраняйте статус обработки: processing, processed, failed_review. Это помогает отличать повтор от незавершённого первого запуска.
- Отвечайте внешнему сервису предсказуемо: повтор уже обработанного события — не авария, а duplicate outcome.
- Задайте TTL только там, где бизнес допускает забывание старых событий; для платежей обычно нужен долгий retention.
Типичные ошибки
- dedupe делают по email или телефону, и разные события одного клиента подавляются ошибочно
- key сохраняют после write, но при падении между write и save возникает повторное действие
- параллельные webhook executions одновременно видят key как отсутствующий
- TTL слишком короткий для поздних retry провайдера
- duplicate ветка возвращает 500, провоцируя новые повторы
Проверка результата
- Два одинаковых payload подряд создают только одну бизнес-запись.
- Параллельная доставка одного event_id не проходит две write-ветки.
- Duplicate execution логируется как skipped/duplicate, а не failed.
- В audit есть idempotency key и ссылка на первичный successful execution.
Где хранить processed events
Лучший вариант для production — Postgres/Redis с уникальным ключом и атомарной вставкой. Google Sheets подходит для небольших сценариев, но хуже защищает от гонок. Если у CRM уже есть внешний id и upsert, можно использовать её как часть idempotency, но всё равно фиксируйте исходный event_id отдельно для расследований.
Сущности и SEO-охват
Ключевые сущности страницы: webhook idempotency, event_id, idempotency key, processed events, duplicate delivery, retry, unique constraint, safe write.
Production-контекст и проверка внедрения
Материал «Webhook idempotency в n8n: как не обработать событие дважды» стоит использовать не только как пример настройки, но и как мини-runbook для внедрения в реальный n8n. Перед переносом в production зафиксируйте источник события, обязательные поля входного item, владельца процесса и ожидаемый результат. Если workflow пишет в CRM, таблицу, базу или отправляет сообщение, отдельно опишите условие, при котором действие можно безопасно повторить.
Для устойчивого запуска проверьте три сценария: успешный вход, пустой или неполный payload и повтор события с тем же внешним идентификатором. Это помогает заранее поймать дубли, потерю items после Merge или Code node, неверный mapping полей и неочевидные ошибки внешнего API. Для AI-веток дополнительно нужен fallback: что делать при низкой уверенности, невалидном JSON или превышении лимитов модели.
Чеклист перед публикацией workflow
- Добавьте тестовый payload без секретов и персональных данных.
- Проверьте retry, error branch, idempotency и ручной override.
- Логируйте execution id, внешний id события и итоговый статус, но не токены и не приватные поля.
- Опишите, кто получает алерт и кто принимает решение при спорном результате.
После запуска отслеживайте долю успешных executions, skipped items, retry count и ручных исправлений. Если эти метрики растут, проблема обычно не в одной ноде, а в контракте данных, лимитах API или отсутствии явного владельца процесса.
Связанные материалы для углубления
- Все рецепты — открыть связанный материал для проверки контекста.
- Workflow JSON — открыть связанный материал для проверки контекста.
- Диагностика — открыть связанный материал для проверки контекста.
- Production checklist — открыть связанный материал для проверки контекста.
FAQ
Чем idempotency отличается от дедупликации клиентов?
Idempotency работает на уровне события: один event_id обрабатывается один раз. Дедупликация клиентов может объединять разные события одного человека.
Можно ли хранить keys в Google Sheets?
Для малого потока можно, но при параллельных событиях лучше Redis или Postgres с уникальным constraint.
Что делать, если provider не даёт event_id?
Соберите ключ из нескольких стабильных полей, но помните о риске ложных дублей. Для платежей лучше искать provider-specific id.