Event-driven архитектура на n8n: как строить автоматизации вокруг событий ¶
Обновлено: 2026-05-29
Короткий ответ ¶
Event-driven архитектура в n8n означает, что workflow запускается не по ручному расписанию, а по факту события: новый webhook, сообщение из очереди, изменение в CRM, поступивший платёж, письмо, тикет или сигнал от другого сервиса. В production такой подход требует не только trigger node, но и контракта события, idempotency key, журналирования, retry/DLQ, контроля порядка обработки и безопасного replay. Если этого нет, один и тот же webhook может создать два лида, платёж может пройти без обновления CRM, а ошибка в downstream API превратится в потерянное событие.
Когда event-driven подход действительно нужен ¶
Event-driven модель стоит использовать, когда действие должно произойти сразу после внешнего события: клиент оплатил заказ, пользователь отправил форму, менеджер поменял статус сделки, партнёр прислал webhook, поддержка получила новый тикет, AI-agent запросил выполнение tool, склад обновил остатки. В таких сценариях расписание вроде “каждые 10 минут проверять API” часто создаёт задержку, лишнюю нагрузку и сложный код сравнения состояний.
Но event-driven подход не нужен везде. Если источник не умеет отправлять события, данные можно безопасно забирать батчем, задержка в 15–60 минут допустима, а порядок обработки важнее мгновенности, cron workflow может быть проще и надёжнее. Хорошее правило: событие должно иметь понятную бизнес-ценность, стабильный идентификатор и понятный lifecycle. Если событие невозможно отличить от дубля, сначала проектируют контракт, а не запускают Webhook node.
Базовая схема event-driven workflow ¶
Минимальная схема в n8n выглядит так: trigger принимает событие, validation node проверяет payload, normalization layer приводит поля к внутреннему формату, idempotency check решает, обрабатывали ли событие раньше, бизнес-ветка выполняет действие, audit log фиксирует результат, а error branch отправляет событие в quarantine или DLQ.
Для webhook-сценария это может быть цепочка: Webhook → Code “validate event” → Postgres “insert idempotency key” → Switch по типу события → CRM/Payments/Email nodes → Audit log → Respond to Webhook. Для очереди: queue consumer или polling node → validation → dedupe → worker workflow → status update. Для email/ticket сценариев: trigger → extraction/classification → routing → human review → update source system.
Главная мысль: event-driven workflow не должен сразу “делать полезное действие”. Сначала он должен понять, что пришло, можно ли этому верить, не было ли этого раньше, и есть ли достаточно данных для безопасного выполнения.
Контракт события ¶
Контракт события — это договор между источником и n8n. Он отвечает на вопросы: кто отправляет событие, какой у него тип, как найти уникальный идентификатор, в какой версии формат payload, какие поля обязательны, какие поля могут отсутствовать, как обрабатывать повторную доставку.
Практичный event envelope может выглядеть так:
{
"event_id": "evt_2026_05_29_000123",
"event_type": "payment.succeeded",
"event_version": "v1",
"occurred_at": "2026-05-29T10:15:30Z",
"source": "checkout",
"tenant_id": "ru-shop-01",
"correlation_id": "ord_98431",
"payload": {
"order_id": "98431",
"amount": 4900,
"currency": "RUB",
"customer_email": "buyer@example.com"
}
}
Если внешний сервис не даёт такой envelope, его создают на первом шаге workflow. Например, event_id можно собрать из source + external_id + status + occurred_at, а correlation_id привязать к заказу, лиду, тикету или платежу. Это резко упрощает логи, поддержку, replay и расследование инцидентов.
Идемпотентность и повторная доставка ¶
Многие webhook-и и очереди доставляют событие повторно: из-за timeout, 500-ответа, сетевой ошибки, ручного replay, повторного сохранения формы или сбоя у провайдера. Поэтому event-driven workflow должен быть идемпотентным: повторная обработка того же события не должна создавать второй заказ, второй лид, второй платёжный статус или второе письмо клиенту.
В n8n это обычно делают через отдельное хранилище: Postgres, Redis, Data Table или внешний backend. Первый шаг после validation пытается записать idempotency_key. Если ключ уже есть со статусом processed, workflow завершает работу безопасным ответом. Если ключ есть со статусом processing и не истёк lock timeout, workflow не запускает бизнес-действие второй раз. Если ключ есть со статусом failed, запускается controlled replay.
Пример SQL-идеи:
insert into event_log (idempotency_key, event_type, status, received_at)
values (:key, :type, 'processing', now())
on conflict (idempotency_key) do nothing;
После этого workflow проверяет, была ли вставка успешной. Это простое место часто отделяет production-архитектуру от “вроде работает на тесте”.
Порядок событий и late events ¶
Не все события приходят в правильном порядке. CRM может сначала прислать deal.updated, потом deal.created; платёжный сервис может повторно отправить старый статус; webhook из формы может приехать раньше, чем файл стал доступен по URL. Поэтому нельзя слепо применять каждое событие к текущему состоянию.
Для важных объектов храните object_version, occurred_at, status_priority или state_machine. Например, если заказ уже в статусе paid, событие payment.pending, пришедшее позже, не должно откатывать статус назад. Если сделка уже закрыта, старый webhook с qualified не должен снова открывать её.
В n8n это можно реализовать через Postgres lookup перед update: достать текущий статус, сравнить timestamp и допустимый переход, затем выполнить update только если переход валиден. Для малых проектов достаточно Switch node + Code node, но для платежей, логистики и CRM лучше описать state machine явно.
Retry, DLQ и replay ¶
Retry нужен для временных ошибок: 429, 502, 503, timeout, сетевой сбой. DLQ нужен для событий, которые нельзя безопасно обработать сейчас: невалидный payload, неизвестный event_type, отсутствующий customer_id, запрещённый статус, ошибка прав доступа. Replay нужен, чтобы после исправления причины обработать событие заново без ручного копирования JSON из логов.
В event-driven workflow важно разделять ошибки на классы. Временная ошибка API — retry с backoff. Ошибка контракта — quarantine с причиной. Бизнес-конфликт — manual review. Неизвестный статус — DLQ и алерт владельцу интеграции.
Хороший DLQ-запись содержит исходный payload, normalized payload, idempotency key, correlation ID, error code, error message, workflow version, node name, retry count и решение: retryable, needs_mapping, needs_manual_review, discarded. Без этих полей replay превращается в гадание.
Что логировать ¶
Минимальный production log для event-driven n8n: event_id, event_type, idempotency_key, correlation_id, source, workflow_id, workflow_version, execution_id, received_at, started_at, finished_at, status, external_object_id, retry_count, error_code. Для PII храните masked value или hash, а не полный email/телефон, если это не нужно для расследования.
Событие должно быть видно как цепочка: получено → проверено → принято/дубль/отклонено → действие выполнено → внешний объект обновлён → ответ отправлен. Если в логах виден только финальный node error, поддержка не сможет понять, потерялось ли событие, было ли оно дублем, или downstream API отклонил запрос.
Production-чеклист ¶
Перед запуском event-driven workflow проверьте: Production URL используется вместо Test URL; источник умеет повторную доставку или вы сами храните raw payload; все события имеют idempotency key; невалидный payload не ломает workflow; 429/5xx идут в retry; unknown event type идёт в DLQ; ручной replay не создаёт дублей; Respond to Webhook возвращает понятный статус; secrets не попадают в execution data; есть owner и runbook; alert срабатывает не на каждый дубль, а на реальные сбои.
Отдельно протестируйте три сценария: один и тот же webhook два раза подряд, событие со старым статусом после нового, и сбой CRM/API после успешного idempotency insert. Эти тесты быстро показывают, готова ли архитектура к production.
Частые ошибки ¶
- Обрабатывать событие до validation/idempotency check.
- Не различать duplicate, retryable failure и bad payload.
- Не хранить raw event для replay.
- Не защищаться от late events и старых статусов.
- Считать webhook delivery равно business success.
Минимальный набор внутренних ссылок ¶
/architecture/data-contracts/— для описания входов и выходов workflow./architecture/idempotency-keys/— для защиты от дублей и replay./architecture/retries-and-dlq/— для повторов, quarantine и controlled replay./architecture/observability-metrics/— для логов, метрик и alerting./playbooks/production-release-checklist/— для релиза и smoke tests.
FAQ ¶
Можно ли делать event-driven архитектуру только на Webhook node? ¶
Можно, если источник стабильно отправляет события и нагрузка небольшая. Но для production обычно нужны validation, idempotency store, audit log, retry/DLQ и отдельный error workflow.
Нужно ли отвечать webhook сразу или после всей обработки? ¶
Если источник ждёт быстрый HTTP-ответ, лучше быстро принять событие, записать его в журнал и обработать асинхронно. Если источник требует синхронный результат, ограничьте workflow по времени и явно обрабатывайте timeout.
Что делать, если событие пришло без event_id? ¶
Соберите idempotency key из доступных стабильных полей: source, object_id, event_type, status, timestamp или hash payload. Главное — документировать правило и использовать его одинаково.
Как понять, что событие потерялось? ¶
Нужен event log с received/processed/failed статусами и мониторингом: количество полученных событий, доля failed, возраст oldest unprocessed event, DLQ size, retry count.
Event-driven подход лучше cron workflow? ¶
Не всегда. Event-driven лучше для быстрых реакций и внешних сигналов. Cron проще для регулярной сверки, backfill, отчётов и источников без webhooks.