n8n: workflow зависает — причины и решение
Вчера сценарий отрабатывал за восемь секунд, сегодня третий час висит со статусом Running и молчит в логах. «n8n зависает» — это четыре разные поломки с одинаковым внешним видом: прокси, нода без таймаута, память, очередь. Ниже — как за пять минут понять, какая из них у вас.
Содержание
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Сначала разделите четыре разных «зависания»
Посмотрите на список Executions и на контейнер — диагноз ставится почти однозначно.
| Что видите | Что на самом деле | Куда смотреть |
|---|---|---|
| Running крутится вечно, но данные в Telegram уже пришли | Выполнение закончилось, событие не дошло до браузера | Push-канал через реверс-прокси |
| Running, время растёт, процесс греет CPU или ест память | Висит конкретная нода или цикл | Таймауты нод, Code, Loop Over Items |
| Статус New и не меняется | В queue mode задачу некому взять | Redis и воркеры |
| Running, хотя контейнер n8n перезапускался | Мёртвая запись от упавшего процесса | OOM, логи, чистка таблицы выполнений |
| Висит всё, интерфейс не открывается | Кончились память, диск или коннекты к БД | docker stats, df -h, pg_stat_activity |
Статус Waiting сюда не входит: нода Wait с паузой больше 65 секунд не держит процесс, а откладывает выполнение в базу и возвращает по расписанию. А Wait в режиме Resume: On Webhook Call без лимита ожидания штатно ждёт хоть неделю.
Диагностика за пять минут
Сначала исключаем инфраструктуру, потом лезем в сценарий.
docker compose logs -n 200 -f n8n
docker stats --no-stream
docker inspect n8n --format '{{.State.OOMKilled}} {{.State.ExitCode}} {{.RestartCount}}'
df -h /var/lib/docker
Ключевая — третья. Если видите такое, дальше можно не искать:
$ docker inspect n8n --format '{{.State.OOMKilled}} {{.RestartCount}}'
true 7
Семь перезапусков и OOMKilled: true означают, что контейнер убивает ядро по памяти, а «зависшие» выполнения — записи, которые никто не закрыл. Подтверждает dmesg -T | grep -i 'Out of memory' на хосте.
Дальше база. Для Postgres:
SELECT id, "workflowId", status, "startedAt", now() - "startedAt" AS age
FROM execution_entity WHERE status IN ('running', 'new') ORDER BY "startedAt";
Для SQLite: sqlite3 ~/.n8n/database.sqlite "SELECT id, workflowId, status, startedAt FROM execution_entity WHERE status IN ('running','new') LIMIT 20;"
Записи старше максимально возможного времени сценария — уже не «выполняется», а мусор. Подробные логи включают N8N_LOG_LEVEL=debug и N8N_LOG_OUTPUT=console; debug даёт десятки мегабайт в час, поэтому ограничьте драйвер логов Docker (max-size: "10m").
Развернуть за пару минут
Готовый образ на VPS MAATRIX: NVMe, AMD EPYC, root-доступ. Локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Развернуть n8nЛожное зависание: сценарий отработал, а браузер не узнал
Самый частый случай у тех, кто поставил n8n за nginx по мануалу в три строки. Спиннер крутится, нода подсвечена как выполняющаяся — но нажмите F5, и выполнение уже success, время работы четыре секунды.
Ход выполнения редактор получает не обычными HTTP-запросами, а по вебсокету на /rest/push. Если прокси не пропускает заголовки Upgrade, канал не поднимается, и в консоли браузера видно:
WebSocket connection to 'wss://n8n.example.com/rest/push?pushRef=8f2c41ae' failed
Второй вариант тоньше: канал рвётся каждые 60 секунд — столько по умолчанию у nginx proxy_read_timeout. Короткие сценарии отрабатывают нормально, «зависают» длинные, а в /var/log/nginx/error.log появляется upstream timed out (110: Connection timed out) while reading response header from upstream.
Рабочий блок:
location / {
proxy_pass http://127.0.0.1:5678;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_read_timeout 3600s;
proxy_buffering off;
}
Применить nginx -t && systemctl reload nginx, проверить в DevTools → Network → фильтр WS: соединение к /rest/push должно получить 101 Switching Protocols и висеть, не переоткрываясь каждую минуту. Если вебсокеты режет что-то по дороге, переключите канал на N8N_PUSH_BACKEND=sse — но тогда proxy_buffering off обязателен.
Честно: этот раздел не ускоряет ни один сценарий — он чинит только то, что вы видите. Но именно здесь чаще всего оптимизируют workflow, который давно закончился. Смежные грабли — в статье про 504 Gateway Timeout.
Нода, которая действительно висит
Если процесс жив, а выполнение идёт минутами — ищите ноду.
HTTP Request без таймаута. Внешний API принял соединение и замолчал — нода ждёт вечно. Откройте Options → Timeout, поставьте явные 30000 мс, там же включите Retry On Fail, Max Tries 3, Wait Between Tries 5000.
Нет общего потолка. По умолчанию EXECUTIONS_TIMEOUT=-1 — выполнение живёт вечно. Рамки:
EXECUTIONS_TIMEOUT=900
EXECUTIONS_TIMEOUT_MAX=3600
Первая — таймаут по умолчанию (15 минут), вторая — потолок, который нельзя превысить в Workflow Settings → Timeout Workflow. Ограничение честное: таймаут проверяется между шагами и ноду, заблокировавшую поток, не прервёт.
Code-нода, которая блокирует всё. while (true) или регулярка с катастрофическим бэктрекингом блокируют event loop Node.js. Симптом узнаваемый: висит не один сценарий, а весь инстанс, интерфейс и healthcheck не отвечают. Лечится выносом кода в отдельный процесс:
N8N_RUNNERS_ENABLED=true
N8N_RUNNERS_MODE=internal
N8N_RUNNERS_TASK_TIMEOUT=60
N8N_RUNNERS_MAX_OLD_SPACE_SIZE=1024
Теперь бесконечный цикл убивает не инстанс, а процесс раннера, и сценарий падает с ошибкой через минуту. В свежих сборках раннеры включены по умолчанию — проверьте docker exec -it n8n n8n --version и лог при старте.
Loop Over Items, замкнутый сам на себя. Выход loop заведён обратно во вход той же ноды, ветка done никуда не ведёт: счётчик items растёт, память тоже. Признак — одна нода отработала сотни раз. Для длинных списков ставьте батч 100–500.
Дедлок на подсценариях. При N8N_CONCURRENCY_PRODUCTION_LIMIT=5 и вызовах Execute Sub-workflow с ожиданием завершения пять родителей займут все слоты и будут ждать подсценарии, которым слотов не осталось. Снаружи — вставшая намертво очередь. Лечится поднятием лимита выше числа одновременных родителей.
Ручной запуск, который ждёт триггер. Waiting for trigger event означает, что сценарий ждёт тестового вызова вебхука. Тестовый URL живёт около двух минут и отличается от продакшн-адреса: продакшн-вызов его не разбудит.
Память, бинарники и разросшаяся база
n8n держит данные всех нод выполнения в памяти: CSV на 200 МБ через шесть нод — это несколько копий массива. Симптома три: сообщение «Execution stopped at this node. n8n may have run out of memory while running it», тихая смерть контейнера с OOMKilled: true или строка FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory.
- Задать кучу явно, 50–60% RAM: на 4 ГБ —
NODE_OPTIONS=--max-old-space-size=2048. - Убрать бинарные данные из памяти:
N8N_DEFAULT_BINARY_DATA_MODE=filesystem, иначе файлы путешествуют между нодами в оперативке. Для больших объёмов — режимs3.
Вторая половина проблемы — база. Инстанс, год проработавший без чистки:
$ du -sh ~/.n8n/database.sqlite
4.7G /home/n8n/.n8n/database.sqlite
Список выполнений открывается десятками секунд, запись блокирует чтение, сценарии выглядят зависшими. Чистка:
EXECUTIONS_DATA_PRUNE=true
EXECUTIONS_DATA_MAX_AGE=168
EXECUTIONS_DATA_PRUNE_MAX_COUNT=20000
EXECUTIONS_DATA_SAVE_ON_SUCCESS=none
EXECUTIONS_DATA_SAVE_ON_PROGRESS=false
EXECUTIONS_DATA_MAX_AGE задаётся в часах: 168 — неделя. Отдельно про EXECUTIONS_DATA_SAVE_ON_PROGRESS: с ним n8n пишет состояние после каждой ноды, и сценарий из тридцати нод превращается в тридцать транзакций — на SQLite с единственным писателем это растягивает выполнение в разы.
После чистки файл SQLite не уменьшится: освобождённые страницы остаются внутри. Включите DB_SQLITE_VACUUM_ON_STARTUP=true, перезапустите контейнер и выключите обратно — на большой базе vacuum занимает минуты. Честная граница SQLite — несколько тысяч выполнений в сутки и один инстанс без воркеров; дальше DB_TYPE=postgresdb (как поднять базу). И банальное: df -h, диск на 100% — записи в базу встают.
Queue mode: Redis, воркеры и записи в Running
При EXECUTIONS_MODE=queue добавляется свой класс зависаний: главный процесс ставит задачу в очередь, а забирать некому. В интерфейсе — статус New, который не двигается. Смотрим очередь:
redis-cli -h 127.0.0.1 -p 6379 LLEN bull:jobs:wait
redis-cli -h 127.0.0.1 -p 6379 LLEN bull:jobs:active
redis-cli -h 127.0.0.1 -p 6379 CONFIG GET maxmemory-policy
Растущий bull:jobs:wait при нулевом bull:jobs:active — задачи есть, брать некому: воркер не запущен, упал или смотрит не туда. Третья команда важнее, чем кажется:
$ redis-cli CONFIG GET maxmemory-policy
1) "maxmemory-policy"
2) "allkeys-lru"
При allkeys-lru Redis под давлением памяти выбрасывает произвольные ключи, включая ключи очереди: задачи исчезают, выполнение навсегда остаётся в New, в логах ничего нет. Нужен noeviction — redis-cli CONFIG SET maxmemory-policy noeviction плюс то же в /etc/redis/redis.conf, иначе после рестарта вернётся прежнее значение.
Что ещё ломает queue mode тихо:
- Разный
N8N_ENCRYPTION_KEYу главного процесса и воркера: воркер не расшифрует учётные данные, задача уйдёт в ретраи. - Разный
QUEUE_BULL_REDIS_DB: главный кладёт в базу 0, воркер слушает 1 — очередь растёт, воркер простаивает. - Нет healthcheck воркера. Включите
QUEUE_HEALTH_CHECK_ACTIVE=trueи проверяйтеcurl -fsS http://127.0.0.1:5678/healthz, ответ —{"status":"ok"}. - Пул соединений к Postgres. У
DB_POSTGRESDB_POOL_SIZEзначение по умолчанию 2. Три воркера с--concurrency=10дают до тридцати параллельных выполнений на два коннекта: запросы встают в очередь, в логе появляетсяConnection terminated due to connection timeout, всё замирает. Поднимите до 10–20 и сверьте сSHOW max_connections;. - Перезапуск на длинном сценарии.
N8N_GRACEFUL_SHUTDOWN_TIMEOUTпо умолчанию 30 секунд: если сценарий идёт десять минут,docker compose restartоборвёт его посередине и оставит запись в Running.
Осиротевшие записи чистятся так — на остановленном n8n и после pg_dump:
UPDATE execution_entity SET status = 'crashed', "stoppedAt" = now()
WHERE status = 'running' AND "startedAt" < now() - interval '2 hours';
Но сначала просто перезапустите инстанс: свежие версии сами помечают осиротевшие выполнения.
Какой сервер нужен, чтобы n8n не зависал
Большая часть описанного выше — не баги n8n, а следствие тесной машины: OOM-killer, медленный диск, нет места под воркеры. Ориентиры из практики:
| Профиль | Конфигурация | Что реально тянет |
|---|---|---|
| Минимум | 2 vCPU / 4 ГБ RAM / 50 ГБ NVMe | n8n, Postgres и Redis в Docker, 500–800 выполнений в сутки, heap 2048 МБ |
| Комфорт | 4 vCPU / 8 ГБ RAM / 100 ГБ NVMe | queue mode с двумя воркерами, AI-ноды, файлы в десятки мегабайт, запас на пики |
| Тяжёлый | 8 vCPU / 16 ГБ RAM / 200 ГБ NVMe | десятки параллельных выполнений, крупные бинарники, отдельный Postgres |
Почему не 2 ГБ: процесс в покое занимает 300–500 МБ, плюс Postgres и Redis. Первый же сценарий с ответом API на 50–100 МБ упирается в лимит кучи — и вы получаете ровно то зависание, ради которого читаете эту статью. Диск только NVMe: база пишется на каждом выполнении.
Локацию выбирайте по тому, куда ходят сценарии. UK (Лондон) — вариант по умолчанию: 10–20 мс до основных европейских точек обмена, то есть быстрые вызовы к европейским API и SaaS, соседство с GDPR-контуром и 40–60 мс до Москвы. Если сценарии дёргают зарубежные ИИ-сервисы и нужен чистый IP — US (Нью-Йорк); если важен 152-ФЗ — RU.
Перед обновлением делайте снапшот и не запускайте образ по тегу latest — пиньте версию в docker-compose.yml. Заказать VPS под n8n в MAATRIX можно картой российского банка, по СБП, криптой или токеном MAAT — иностранная карта не нужна даже для лондонской площадки. Установка с нуля — в статье про настройку n8n на VPS, типовые поломки — в материале про частые ошибки n8n.
Развернуть за пару минут
Готовый образ на VPS MAATRIX: NVMe, AMD EPYC, root-доступ. Локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Развернуть n8nОбсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Частые вопросы
Выполнение висит в Running сутки, можно его убить?
Кнопка Stop на «мёртвой» записи часто не срабатывает — процесса за ней уже нет. Перезапустите инстанс: свежие версии сами переводят осиротевшие выполнения в crashed, и только если этого не произошло — правьте статус в базе через UPDATE с бэкапом.
Почему сценарий висит в редакторе, но в базе он success?
Это разрыв push-канала на /rest/push. Добавьте в nginx заголовки Upgrade и Connection и поднимите proxy_read_timeout до 3600s.
Как ограничить время выполнения?
Поставьте EXECUTIONS_TIMEOUT=900 и EXECUTIONS_TIMEOUT_MAX=3600 глобально плюс явный Timeout в опциях каждой ноды HTTP Request. Общий таймаут проверяется между шагами и не прервёт ноду, заблокировавшую поток.
Нужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.