Обработка ошибок и устойчивость

При подготовке курса мы разбирали контент-конвейер кофейни «Зерно» из модуля 3 и искали места, через которые один и тот же пост мог бы выйти дважды. Нашли две такие дыры. Их закрывают узлы «Взять в работу» и «Отклонено», которые вы уже поставили в уроках 3.3 и 3.6. Настоящего дубля в прогоне не случилось: конвейер стоял выключенным. В этом уроке разберём, почему защита устроена именно так, как убедиться, что она работает, и что делать, если дубль всё же вышел. А ещё научим конвейер сообщать о сбое в Telegram и подставлять запасную модель, если основная не ответила.

Чему научитесь в этом уроке:
• понимать, от чего защищают статусы темы, и проверять эту защиту без единого поста;
• получать в Telegram сообщение, когда любой ваш сценарий упал;
• включать запасную модель и проверять её заведомо неверным именем основной;
• отличать сбой шлюза от кончившегося лимита ключа.

Общие правила надёжности вы уже видели в треке 2, в уроке «Надёжность: когда брифинг не пришёл». Здесь повторять их не будем. У маркетолога своя цена ошибки: упавший брифинг можно запустить ещё раз, а вышедший пост обратно не заберёшь. Поэтому начнём с дублей.

Откуда берутся дубли постов

Представьте доску с карточками задач в кофейне. Если бариста берёт карточку «написать пост» и не переворачивает её, второй бариста возьмёт ту же карточку. В контент-плане роль карточки играет строка таблицы, а перевернуть её значит сменить статус. Если бы статус менялся только в конце, когда пост вышел, остались бы две дыры. Поэтому в уроке 3.3 узел «Взять в работу» стоит в самом начале.

  • Дыра первая: Telegram упал, ВК уже вышел. Отметка published ставится после поста в Telegram. Без статуса in_progress строка при сбое Telegram осталась бы new, и следующий запуск опубликовал бы во ВКонтакте тот же пост снова.
  • Дыра вторая: тема ждёт одобрения. Пока черновик лежит у вас в Telegram и ждёт кнопки, тема без in_progress числилась бы new. Запуск в среду взял бы тему понедельника второй раз, и после двух одобрений вышли бы два одинаковых поста.
Схема статусов строки контент-плана: new (тема ждёт в плане) → in_progress (сразу, как тему взяли) → published (после поста, в очередь больше не попадёт) или rejected (нажали «Отклонить», тоже не вернётся сама). Ниже две плашки: «Дыра 1: Telegram упал, а ВКонтакте уже вышел» и «Дыра 2: черновик ещё ждёт вашей кнопки» — что случилось бы без статуса «в работе».

Как устроена защита, которую вы уже собрали

Защита стоит в вашем конвейере с модуля 3. Откройте контент-конвейер и найдите в нём три места. Здесь ничего не нужно собирать заново, только понять, зачем каждое из них.

  1. «Взять в работу» (урок 3.3) стоит сразу после «Следующая тема». Это узел Data Table (работа с таблицей данных n8n): действие Update, условие id равен {{ $('Следующая тема').first().json.id }}, поле status = in_progress. Почему так рано: тема должна стать занятой до всего долгого и ненадёжного, то есть до модели, картинки и ожидания вашей кнопки.
  2. «Отклонено» (урок 3.6) стоит на ветке «нет» после одобрения и записывает status = rejected. Без него отклонённая тема так и осталась бы in_progress, и вы не отличили бы её от упавшего запуска.
  3. Копирайтер берёт тему через $('Следующая тема'), а не со своего входа: на вход ему приходит ответ узла «Взять в работу», и поля topic там может не оказаться (урок 3.3).

Что это даёт. Тема в работе больше никому не достанется. Если запуск упал на середине, строка застрянет в in_progress: в таблице это видно, повторно её не опубликуют, разбираете её руками. Как замечать такие строки в еженедельном разборе, покажем в уроке 5.3.

Как убедиться, что защита работает. Публиковать для этого ничего не нужно. Соберите отдельный тестовый сценарий всего из двух узлов, «Следующая тема» → «Взять в работу», с теми же настройками, что в конвейере, и запустите его дважды подряд. Должны взяться две разные темы. В прогоне первый запуск взял тему 2, второй тему 3, повтора не было; оба запуска видны в разделе Executions (журнал запусков сценария). После проверки верните статусы этих двух тем в new, чтобы план остался рабочим.

Если пост всё же ушёл дважды. Удалите дубль руками в Telegram и во ВКонтакте, строке плана поставьте published, а причину запишите в журнал. Потом проверьте двумя тестовыми запусками, что «Взять в работу» по-прежнему стоит сразу после «Следующей темы». Это совет: в прогоне курса дубля не было, и этот порядок вживую не проверяли.

Уведомление о сбое в Telegram

Сценарий по расписанию упал ночью, а вы узнаёте об этом в понедельник по пустому журналу. Нужен сторож, который сразу позвонит. В n8n это отдельный сценарий с узлом Error Trigger: он запускается сам, когда падает любой сценарий, к которому его подключили, и получает описание сбоя. В прогоне такой сценарий назывался «Т3: уведомление о сбое».

  1. Error Trigger «Ошибка в сценарии».
  2. Code «Текст уведомления»: собирает короткое сообщение из описания сбоя.
  3. Telegram «Мне в Telegram»: Send Message, Chat ID <ваш номер>, Text {{ $json.text }}, Append n8n Attribution выключен. Chat ID здесь номер вашего личного чата с ботом, как его узнать, показано в уроке трека 2 «Бот в Telegram». Append n8n Attribution дописывает к сообщению подпись, что оно отправлено через n8n; себе она не нужна.

Код узла «Текст уведомления», дословно из прогона:

// Короткое сообщение о сбое: какой сценарий, на каком шаге, что случилось, ссылка на запуск
const e = $json.execution || {}, w = $json.workflow || {};
const text = '⚠️ Сбой сценария «' + (w.name || '?') + '»\n' +
  'Шаг: ' + (e.lastNodeExecuted || '?') + '\n' +
  'Ошибка: ' + String(e.error?.message || 'нет текста').slice(0, 300) + '\n' +
  (e.url ? 'Запуск: ' + e.url : '');
return [{ json: { text } }];

Чтобы проверить сторожа, не роняя рабочий сценарий, в тот же сценарий добавляют тестовую ветку: Manual Trigger «Тест вручную» → Code «Пример ошибки» → тот же «Текст уведомления». «Пример ошибки» подсовывает данные, похожие на настоящий сбой:

// Пример данных, которые n8n передаёт при сбое — для проверки уведомления
return [{ json: { workflow: { name: 'Т3: контент-конвейер (тест)' }, execution: { lastNodeExecuted: 'Во ВКонтакте (текст)', error: { message: 'Тестовое уведомление: настоящего сбоя нет' } } } }];

В прогоне тестовую ветку запустили один раз, и сообщение пришло в Telegram. Настоящий сбой рабочего сценария мы специально не устраивали. Имя шага «Во ВКонтакте (текст)» в коде взято из сборки курса. В вашем конвейере узел может называться иначе, для проверки это неважно: «Пример ошибки» только подставляет текст.

Подключение делается в каждом рабочем сценарии: ⋯ → Settings → Error Workflow → «Т3: уведомление о сбое». Здесь была заминка. Пока сценарий уведомления не опубликован, n8n не даёт его выбрать и пишет: «The selected error workflow has no published version». Сначала нажмите Publish в сценарии уведомления, потом выбирайте его в настройках. В прогоне его подключили к рабочим сценариям модулей 3 и 4: контент-конвейеру, разбору конкурента, недельному отчёту и слайду.

Запасная модель

Если основной поставщик кофе не привёз зерно, кофейня звонит запасному. У узла Basic LLM Chain есть такой же запасной номер: параметр Enable Fallback Model. После его включения у узла появляется второй вход Model. Первый вход занимает основная модель, второй запасная. Если основная ответила ошибкой, узел сам спрашивает запасную.

Проверяли так: основной поставили заведомо несуществующую модель google/no-such-model-test, запасной рабочую google/gemini-3.6-flash. В разделе Executions у этого запуска видно: основная за 0,2 с ответила «The resource you are requesting could not be found», запасная ответила за 5,9 с, пост получен. Неверное имя удобно тем, что ломает только основную модель, а запасная работает как обычно.

Запасная модель спасает от отказа, но не от долгого ответа. Для долгих задач в узле модели есть Options → Timeout и Max Retries. В уроке 4.3 разбор 50 отзывов без этих настроек падал с «Request timed out» примерно через 10 с; помогли Timeout 180000 (это миллисекунды, три минуты) и Max Retries 2.

Повторы запроса и необязательная картинка

Картинку к посту вы делали в уроке 3.4 отдельным HTTP-запросом. Такой запрос иногда падает на секунду. В узле «Картинка» откройте Settings: Retry On Fail, 3 раза через 5 с, и On Error = Continue. Тогда пост без картинки всё равно дойдёт до вас на одобрение.

Есть ловушка, на которой споткнулись в прогоне, и узел против неё у вас стоит с урока 3.6. Если в сообщении узла Send and Wait стоит выражение, которое заглядывает в упавший узел «Картинка», падает уже узел одобрения с ошибкой «reading ‘trim’». Поэтому текст заранее собирает узел Code «Черновик», а Send and Wait берёт из него только готовое {{ $json.msg }}. Проверьте, что в вашем конвейере так и есть.

Лимиты и сбой шлюза

Все запросы к моделям идут через CloseRouter. Это шлюз, то есть посредник между n8n и моделями: n8n отправляет запрос ему, а он передаёт его нужной модели. У ключа CloseRouter для учеников стоит лимит 5 $ в месяц, он задаётся в кабинете CloseRouter у самого ключа. По задумке, когда лимит кончится, запросы перестанут проходить до следующего месяца; в прогоне курса лимит не исчерпывали, так что это не проверено. Но не каждый отказ значит лимит. При подготовке курса, вечером 07.10.2026, все модели картинок отвечали «500 internal_error», хотя ключ был почти не потрачен, а баланс аккаунта составлял 5,50 $. Это был сбой шлюза. Отличить его просто: неудачные запросы в «Использование» кабинета не попадают, и расход за этот вечер не вырос. Сбой шлюза пережидают, лимит поднимают или ждут нового месяца.

Если не получилось

  • В настройках Error Workflow нельзя выбрать сценарий уведомления. Он не опубликован. Нажмите Publish в сценарии «уведомление о сбое» и вернитесь в настройки.
  • Тестовая ветка не прислала сообщение. Проверьте Chat ID: это номер вашего личного чата с ботом, а не номер канала. Посмотрите, дошёл ли запуск до узла «Мне в Telegram» и какой узел красный.
  • Тестовый сценарий статусов дважды взял одну тему. Узел «Взять в работу» не обновляет строку: проверьте условие по id и что status пишется в нужную колонку.
  • В конвейере нет «Взять в работу» или «Отклонено». Значит, он собран по старой версии модуля 3. Сверьте его с уроками 3.3 и 3.6, там эти узлы описаны, и проверьте защиту двумя тестовыми запусками.
  • С неверной основной моделью узел всё равно падает. Проверьте, что Enable Fallback Model включён и запасная модель подключена ко второму входу Model.
  • Одобрение падает с «reading ‘trim’». Текст сообщения Send and Wait ссылается на упавшую «Картинку». В «Одобрении» должно стоять только {{ $json.msg }} из «Черновика».

Контрольный вопрос. Черновик понедельника ждёт вашего одобрения, а в среду конвейер запускается снова. Что не даст ему взять ту же тему?

АУзел «Картинка» с повтором 3 раза через 5 с
БЗапасная модель во втором входе Model
ВСтатус in_progress, который ставит узел «Взять в работу» сразу после выбора темы
ГСценарий уведомления о сбое

Подсказка: Вспомните урок 3.3: в какой момент тема перестаёт числиться свободной.

На курсе задания проверяются автоматически. Подобрать курс

Контрольный вопрос. Вечером все запросы к моделям картинок возвращают 500 internal_error, а расход в «Использовании» кабинета не растёт. Что это скорее всего?

АКончился месячный лимит ключа
БСбой шлюза, который стоит переждать
ВОшибка в коде узла «Черновик»
ГНеверный Chat ID в уведомлении

Подсказка: Вспомните, попадают ли неудачные запросы в «Использование» и что было с ключом в прогоне.

На курсе задания проверяются автоматически. Подобрать курс

Контрольный вопрос. Что нужно, чтобы n8n прислал вам сообщение о сбое рабочего сценария? Выберите все подходящие.

Выберите все верные варианты.

АВключить Enable Fallback Model в узле модели
БОпубликовать сценарий с Error Trigger
ВВ настройках рабочего сценария выбрать его в Error Workflow
ГУказать в узле Telegram свой номер в Chat ID

Подсказка: Проследите путь сообщения: кто ловит сбой, как он узнаёт о вашем сценарии и куда отправляет текст.

На курсе задания проверяются автоматически. Подобрать курс

Задание. МИССИЯ «Сторож и запасной». (1) Соберите сценарий уведомления: Error Trigger → Code «Текст уведомления» (код из урока) → Telegram на ваш номер, и тестовую ветку Manual Trigger → Code «Пример ошибки» → тот же «Текст уведомления». Запустите тестовую ветку один раз. (2) Опубликуйте сценарий уведомления и выберите его в Settings → Error Workflow в своих рабочих сценариях модулей 3 и 4. (3) В одном сценарии с Basic LLM Chain включите Enable Fallback Model, основной поставьте google/no-such-model-test, запасной вашу рабочую модель, запустите один раз, затем верните основную модель на место. Приложите: (а) скриншот сценария уведомления целиком; (б) скриншот пришедшего в Telegram тестового сообщения; (в) скриншоты Settings → Error Workflow хотя бы двух рабочих сценариев; (г) скриншот запуска с запасной моделью, где видна ошибка основной и ответ запасной; (д) 1–2 фразы: что вы будете делать, если пост всё же выйдет дважды. Принято, если: в Telegram пришло сообщение со строками «Шаг» и «Ошибка» от тестовой ветки; сценарий уведомления опубликован и выбран в Error Workflow минимум у двух рабочих сценариев; в запуске с запасной моделью основная модель вернула ошибку, а результат получен от запасной; основная модель после проверки возвращена; ответ про дубль называет удаление дубля в обоих каналах и статус published; на скриншотах не видны ключи, токены и номер чата.

Подсказка: Если Error Workflow не даёт выбрать сценарий, перечитайте абзац про публикацию. Если запуск с неверной моделью просто падает, посмотрите, к какому входу узла подключена запасная.

✅ Готово, если: программа запускается без ошибок и выводит то, что просят в задании.

На курсе задания проверяются автоматически. Подобрать курс

Что дальше

Ваши конвейеры теперь не публикуют дважды и сообщают о сбое. Следующий шаг — масштаб: в уроке 5.2 один и тот же контент-конвейер будет писать для трёх клиентов с разным тоном, а брендбуки и каналы будут лежать в таблице.

Итог:
• защита от дублей стоит с модуля 3: тема получает статус in_progress сразу, как её взяли, а отклонённая получает rejected, поэтому ни упавший Telegram, ни ожидание одобрения не дают второго поста;
• защиту проверяют без публикаций: два запуска тестового сценария подряд должны взять разные темы;
• сценарий с Error Trigger присылает в Telegram сообщение о сбое, его проверяют тестовой веткой и подключают через Settings → Error Workflow только после публикации;
• запасную модель включают параметром Enable Fallback Model и проверяют заведомо неверным именем основной;
• у «Картинки» повтор 3 раза через 5 с и Continue, текст для одобрения заранее собирает Code «Черновик»;
• ошибка 500 при нетронутом расходе говорит о сбое шлюза, лимит тут ни при чём.

← Назад  ·  ↑ В начало урока  ·  ⌂ В начало курса  ·  Вперёд →

Школа Виктора Комлева