Документация Triggo
Конструктор workflow

Обработка ошибок

Как Triggo обрабатывает сбои шагов — повторы, continue-on-failure, предохранители и авто-пауза.

Обработка ошибок

Реальные интеграции ломаются. API падают, токены протухают, лимиты запросов срабатывают, сеть икает. В исполнителе Triggo есть четыре слоя обработки ошибок, которые включаются при сбое шага, — у каждого своя задача и своё поведение по умолчанию. Понимание этих слоёв — разница между workflow, который тихо восстанавливается, и тем, что будит вас в 3 часа ночи.

Эта страница рассказывает, что происходит при сбое шага, что можно настроить и как система защищает ваши workflow (и ваш кошелёк) от сломанной интеграции.

Когда шаг падает (по умолчанию)

По умолчанию упавший шаг останавливает запуск. Исполнитель пишет в журнал событие step_failed, помечает запуск pipeline как неуспешный и останавливается. Всё, что ниже по потоку от этого шага, не выполняется.

Два важных свойства такой остановки:

  • Отката нет. Завершённые шаги сохраняют свои выходы. Если шаг A записал строку в Google Sheets, а шаг B упал, строка остаётся записанной. Triggo — event-sourced, а не транзакционная система; «отменить» побочный эффект, который коннектор уже произвёл, нельзя. Просто дальнейшие шаги не выполнятся.
  • Журнал сохраняет всё. Все предыдущие события step_completed, их входы и выходы — всё осталось, видимо в детальном представлении запуска. Именно это позволяет отладить сбой и перезапустить с точки падения после исправления.

Это поведение можно изменить для отдельного шага двумя ручками: retries (повторы) и continue-on-failure. Обе — по явному включению.

Повторы (retries)

Повторы по умолчанию выключены. Конфигурация повторов в исполнителе задаёт maxRetries: 0. Шаг, бросивший исключение, выполняется ровно один раз и падает. Это удивляет тех, кто приходит с платформ, где каждый шаг автоматически повторяется три раза, — Triggo так не делает.

Чтобы включить повторы, задайте maxRetries у шага. Когда повторы включены, исполнитель использует экспоненциальный backoff:

delay(attempt) = baseIntervalMs * 2^(attempt - 1)

Задержка ограничена 30 секундами (DEFAULT_MAX_DELAY_MS). Опциональный симметричный jitter (jitterMs) добавляет ±jitterMs случайного шума, чтобы разнести повторы из множества параллельных запусков.

Пример: maxRetries=3, baseIntervalMs=1000

ПопыткаСырая задержка (мс)После лимита 30 с
1-й повтор (попытка 1 не удалась)1 × 2⁰ = 1 0001 000 мс (1 с)
2-й повтор (попытка 2 не удалась)1 × 2¹ = 2 0002 000 мс (2 с)
3-й повтор (попытка 3 не удалась)1 × 2² = 4 0004 000 мс (4 с)

После 4-й попытки (исходная + 3 повтора) ошибка пробрасывается, и шаг помечается неуспешным. Общая стоимость по времени: около 7 секунд сна плюс сами вызовы коннектора.

Ограничение 30 секунд важнее, когда baseIntervalMs большой или maxRetries высокий. С baseIntervalMs: 5000, maxRetries: 5 последовательность будет 5 с, 10 с, 20 с, 30 с (обрезано с 40 с), 30 с (обрезано с 80 с) — последние две попытки сидят на потолке.

Переопределения для шага

Конфиг повторов — на уровне шага. Общей настройки для рабочего пространства нет и способа глобально включить повторы тоже нет — вы включаете их на тех шагах, где повтор имеет смысл (временные сетевые ошибки, нестабильность третьей стороны), и оставляете выключенными там, где не имеет (ошибки аутентификации, ошибки валидации, которые не исчезнут при второй попытке). Опциональный предикат shouldRetry(error) => boolean может дополнительно отфильтровать, какие ошибки стоит повторять; классификация на уровне коннектора использует RETRYABLE_ERROR_CODES из @triggo/shared.

Continue-on-failure

Иногда хочется, чтобы шаг упал без остановки запуска — некритичное уведомление, запись аналитики, best-effort-обогащение. Установите флаг continueOnFailure у шага, и исполнитель:

  1. Поймает сбой (включая брошенные ошибки, возвращённые результаты-сбои и таймауты).
  2. Запишет в журнал событие step_failed_continued вместо step_failed.
  3. Продолжит выполнение. Нижестоящие узлы будут выполняться.

Это поведение покрыто тестом, который проверяет, что таймауты, брошенные ошибки и явные результаты-сбои — все идут по этому пути, если флаг установлен. Когда он выключен (по умолчанию), те же ошибки останавливают запуск как обычно.

Что видят нижестоящие узлы

У упавшего-но-продолженного шага нет выхода. Сопоставления полей, ссылающиеся на его выходы ({{failed_step.foo}}), разрешаются в undefined — то же поведение, что и при ссылке на узел, который не запускался. О том, как распространяется undefined, см. Сопоставление полей: inline-шаблоны приводят его к пустой строке, whole-value-шаблоны сохраняют undefined, а валидация обязательных полей на границе следующего коннектора — это то место, где обычно всплывает проблема.

Если используете continueOnFailure, исходите из того, что нижестоящим узлам, возможно, придётся обрабатывать отсутствующие данные. Поставьте Code node или условие после возможно-падающего шага, чтобы ветвиться по наличию полезного выхода.

Предохранитель (circuit breaker)

Предохранитель защищает интеграции, а не отдельные шаги. Он работает на уровне интеграции (ключ — код интеграции, например google-sheets), хранится в Redis и общий для всех workflow в рабочем пространстве, использующих эту интеграцию.

Пороги:

  • Порог сбоев: 5 сбоев в окне сбоев размыкают предохранитель.
  • Окно сбоев: 300 секунд (5 минут). Сбои за пределами этого окна не учитываются.
  • Время остывания: 60 секунд. Пока предохранитель разомкнут, каждый вызов этой интеграции коротко закрывается ошибкой breaker-open вместо реального обращения к внешнему API.

Успешный вызов сбрасывает счётчик сбоев. По истечении cooldown предохранитель замыкается сам — ручного вмешательства не нужно.

Что вы увидите при разомкнутом предохранителе

Шаги, обращающиеся к сломанной интеграции, падают быстро с кодом breaker-open вместо зависания на таймаутах. Это система защищает внешний API от молотящих запросов во время сбоя и защищает ваши workflow от длинных каскадов ожидания. Если вы видите breaker-open в нескольких запусках — это сигнал: проблема в самой интеграции, а не в вашем конкретном шаге.

Восстановление

Два пути:

  1. Подождать. Через 60 секунд без новых учтённых вызовов предохранитель снова пропустит запросы. Если внешний API восстановился, следующий вызов пройдёт и счётчик сбросится.
  2. Исправить первопричину. Если интеграция действительно сломана (протухшие учётные данные, повёрнутые ключи, изменения схемы), предохранитель будет просто продолжать размыкаться, когда cooldown истечёт. Исправьте учётные данные или настройки на странице Connections, а затем дайте следующему плановому запуску проверить исправление.

Авто-пауза

Самый внешний слой. Если у pipeline 3 подряд упавших запуска, исполнитель автоматически останавливает его — статус переходит в stopped, подписки на вебхуки деактивируются, а в связанный чат-тред отправляется системное сообщение с объяснением причины.

Порог — CONSECUTIVE_FAILURE_THRESHOLD = 3 в. Счётчик живёт в Redis (autopause:{pipelineId}:failures) и сбрасывается при следующем успешном запуске или когда pipeline поставлен на паузу вручную.

Зачем это

Авто-пауза — это ограничитель радиуса поражения. Сломанный pipeline — неправильные учётные данные, несовпадение схемы коннектора, триггер, срабатывающий на плохих данных, — может пережечь вашу квоту запусков, засыпать вас уведомлениями об ошибках и накрутить расходы на внешние сервисы (токены OpenAI, доставка вебхуков, отправка email) столько, сколько расписание или вебхук будет его подбрасывать. Три страйка — и платформа останавливает кровотечение.

Это жёсткая остановка, а не повтор. После авто-паузы pipeline остаётся остановленным, пока вы его не реактивируете.

Как восстановиться

Когда pipeline на авто-паузе или запуск упал:

  1. Откройте детальное представление запуска для последнего сбоя. Прочитайте сообщение об ошибке на упавшем шаге. См. Отладка запусков, чтобы проследить поток данных через запуск.
  2. Исправьте первопричину. Обновите учётные данные, поправьте сопоставление полей, исправьте нижестоящую схему — что бы там ни было на самом деле. Повтор или реактивация без исправления просто упрутся в ту же стену.
  3. Повторите упавший запуск (replay), если хотите продолжить с места остановки. Replay переиспользует журнал исходного запуска, так что уже успешные шаги не выполнятся повторно — исполнитель продолжит с точки падения.
  4. Реактивируйте pipeline из детального представления, когда будете уверены в исправлении. Это снова включит подписки на вебхуки и расписания.

Смотрите также

  • Отладка запусков — чтение журнала, поиск упавшего шага, отслеживание данных.
  • Лимиты — таймаут шага (30 с), таймаут pipeline (300 с), per-user лимит запусков.
  • Справочник Code Node — как ошибки из Code node попадают в отчёт.
  • Сопоставление полей — как undefined-выходы упавшего-но-продолженного шага распространяются.

On this page