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.