Перейти к содержанию

Retries и dead-letter queue в n8n: безопасная обработка сбоев

Обновлено: 2026-05-29

Открыть мой план

Короткий ответ

Retries помогают пережить временные сбои API, лимиты и сетевые ошибки, а DLQ сохраняет события, которые нельзя обработать автоматически. В n8n важно разделять retryable ошибки, validation errors и бизнес-отказы. Правильная схема включает лимит попыток, backoff, idempotency key, DLQ-хранилище, ручной triage и controlled replay. Без DLQ workflow либо теряет события, либо бесконечно повторяет плохой payload.

Какие ошибки нужно повторять, а какие нет

Не всякая ошибка заслуживает retry. Временные ошибки — 429, 500, 502, 503, 504, network timeout, временная недоступность CRM, Redis или платежного API — обычно можно повторять. Ошибки контракта — нет телефона, неправильный enum, неизвестная версия payload, запрещённый статус — не исправятся повтором. Ошибки прав — 401, 403, expired token — требуют ротации credentials или reauth. Бизнес-отказ — “клиент уже закрыт”, “счёт отменён”, “товара нет” — должен перейти в controlled status, а не в бесконечный retry.

Перед проектированием retry составьте таблицу ошибок: код, причина, retryable, максимальное число попыток, задержка, куда отправлять после исчерпания, кто владелец. Это простая таблица, но именно она превращает workflow из “надеемся, что пройдёт” в управляемую систему.

Retry On Fail, Wait и ручной backoff

В n8n часть ошибок удобно обрабатывать настройкой Retry On Fail у node. Это хороший вариант для простых HTTP/API вызовов, где достаточно повторить тот же запрос через фиксированную задержку. Но для production часто нужен явный control flow: после ошибки определить тип, увеличить attempt count, подождать, записать лог, проверить лимит и только потом повторить.

Пример backoff-политики:

Ошибка Первая задержка Макс. попыток После лимита
429 rate limit из Retry-After или 60 сек 5 DLQ rate_limited
502/503/504 30 сек, 2 мин, 10 мин 4 DLQ upstream_unavailable
timeout 20 сек, 1 мин, 5 мин 3 DLQ timeout
400 validation 0 0 quarantine bad_payload
401/403 0 0 incident credential_issue

Такой подход не даёт одному плохому событию забить очередь и не создаёт лавину повторов во внешний API.

Что такое DLQ в контексте n8n

DLQ — это dead-letter queue, то есть место, куда попадают события, которые основной workflow не смог обработать автоматически. В n8n DLQ часто делают не как встроенную магическую очередь, а как паттерн: отдельная таблица Postgres, Data Table, Google Sheet для маленьких процессов, S3/лог-хранилище или отдельный workflow. Для production лучше Postgres или отдельная queue/storage система.

Минимальная DLQ-таблица:

CREATE TABLE n8n_dead_letters (
  id bigserial PRIMARY KEY,
  dlq_status text NOT NULL DEFAULT 'new',
  event_type text,
  idempotency_key text,
  correlation_id text,
  attempt_count int DEFAULT 0,
  error_code text,
  error_message text,
  payload jsonb NOT NULL,
  last_execution_id text,
  owner text,
  created_at timestamptz DEFAULT now(),
  updated_at timestamptz DEFAULT now()
);

DLQ должна хранить исходный payload, нормализованную ошибку, idempotency key, correlation ID и last execution. Без этого triage превращается в гадание по скриншотам.

Архитектура workflow с DLQ

Базовая схема: Trigger → Contract validation → Idempotency reservation → Business action → Success update. Если validation не прошёл — событие идёт в quarantine. Если внешнее API вернуло retryable ошибку — срабатывает retry policy. Если попытки исчерпаны — запись в DLQ. Если ошибка credentials/security — incident workflow. Если бизнес-отказ — controlled business status.

DLQ лучше выносить в отдельный sub-workflow write_dead_letter. Тогда все production workflow пишут ошибки одинаково. Sub-workflow должен принимать payload, error_code, error_message, correlation_id, idempotency_key, workflow_name, execution_id, owner, retry_policy. Это упрощает поддержку: один формат, один triage, один replay.

Replay workflow

Replay должен быть отдельным workflow, а не ручным “execute previous failed execution” без фильтров. Он выбирает DLQ-записи по статусу, проверяет owner approval, делает dry-run, повторно валидирует payload, проверяет idempotency, запускает основной processing sub-workflow и обновляет DLQ status.

Псевдологика replay:

const row = $json;
if (!['ready_for_replay', 'fixed'].includes(row.dlq_status)) {
  throw new Error('dlq_status_not_replayable');
}
if (!row.idempotency_key) {
  throw new Error('idempotency_key_required_for_replay');
}
return [{ json: { ...row.payload, replay: true, replay_dlq_id: row.id } }];

После replay не удаляйте DLQ-запись сразу. Поставьте replayed_success или replayed_failed, сохраните новый execution ID и результат. Это нужно для аудита и повторного анализа.

Poison messages и защита от бесконечных циклов

Poison message — событие, которое всегда ломает обработку: неверный формат, неожиданный enum, слишком большой payload, prompt injection, сломанный файл, бизнес-состояние, которое workflow не поддерживает. Если такой payload бесконечно возвращать в очередь, он будет тратить ресурсы и скрывать реальные проблемы. Поэтому лимит попыток обязателен.

Ещё одна опасность — error workflow, который сам падает и снова вызывает error workflow. Для alerting делайте отдельный безопасный путь: минимальный payload, no retry storm, throttling, запрет отправки огромного body в Slack/Telegram. Для AI workflow добавьте лимит tool calls и проверку стоимости, иначе retry может умножить LLM-затраты.

Мониторинг retries и DLQ

В production нужно видеть не только “workflow failed”, но и: сколько событий в retry, сколько в DLQ, средний возраст DLQ, топ error_code, топ upstream сервисов, сколько replay прошло успешно, сколько повторно упало, сколько событий stuck in processing. Настройте алерты: DLQ старше SLA, резкий рост 429, много credential_issue, replay success rate ниже нормы, retry storm за последние 10 минут.

Хорошая метрика — business_loss_risk: сколько событий в DLQ влияют на клиентов или деньги. Один failed enrichment может подождать, а один failed payment webhook должен поднимать инцидент.

Production checklist

Перед запуском проверьте: ошибки классифицированы; retry имеет лимит; backoff не нарушает rate limits; есть idempotency key; DLQ хранит payload и correlation ID; replay workflow требует фильтр и approval; poison messages не зацикливаются; alerting настроен по error_code; credentials errors не повторяются бесконечно; payload с PII маскируется в логах; владелец DLQ определён; есть инструкция triage.

FAQ

Нужно ли делать DLQ для каждого workflow?

Для production — да, но лучше через общий sub-workflow записи в DLQ, чтобы формат был единым.

Retry On Fail достаточно?

Для простых transient ошибок — часто да. Для денег, CRM, очередей и replay нужен явный retry policy и DLQ.

Можно ли хранить DLQ в Google Sheets?

Для маленького MVP можно, но для production лучше Postgres/очередь/надёжное хранилище с правами, audit и фильтрами.

Что делать с 401/403?

Обычно не повторять автоматически. Это credential/permission incident: отключить affected workflow, обновить credentials, проверить scope и только потом replay.

Как избежать дублей при replay?

Каждый replay должен проходить через idempotency check и не выполнять бизнес-действие повторно, если ключ уже succeeded.