Обработка ошибок
Как 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 000 | 1 000 мс (1 с) |
| 2-й повтор (попытка 2 не удалась) | 1 × 2¹ = 2 000 | 2 000 мс (2 с) |
| 3-й повтор (попытка 3 не удалась) | 1 × 2² = 4 000 | 4 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 у шага, и исполнитель:
- Поймает сбой (включая брошенные ошибки, возвращённые результаты-сбои и таймауты).
- Запишет в журнал событие
step_failed_continuedвместоstep_failed. - Продолжит выполнение. Нижестоящие узлы будут выполняться.
Это поведение покрыто тестом, который проверяет, что таймауты, брошенные ошибки и явные результаты-сбои — все идут по этому пути, если флаг установлен. Когда он выключен (по умолчанию), те же ошибки останавливают запуск как обычно.
Что видят нижестоящие узлы
У упавшего-но-продолженного шага нет выхода. Сопоставления полей, ссылающиеся на его выходы ({{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 в нескольких запусках — это сигнал: проблема в самой интеграции, а не в вашем конкретном шаге.
Восстановление
Два пути:
- Подождать. Через 60 секунд без новых учтённых вызовов предохранитель снова пропустит запросы. Если внешний API восстановился, следующий вызов пройдёт и счётчик сбросится.
- Исправить первопричину. Если интеграция действительно сломана (протухшие учётные данные, повёрнутые ключи, изменения схемы), предохранитель будет просто продолжать размыкаться, когда cooldown истечёт. Исправьте учётные данные или настройки на странице Connections, а затем дайте следующему плановому запуску проверить исправление.
Авто-пауза
Самый внешний слой. Если у pipeline 3 подряд упавших запуска, исполнитель автоматически останавливает его — статус переходит в stopped, подписки на вебхуки деактивируются, а в связанный чат-тред отправляется системное сообщение с объяснением причины.
Порог — CONSECUTIVE_FAILURE_THRESHOLD = 3 в. Счётчик живёт в Redis (autopause:{pipelineId}:failures) и сбрасывается при следующем успешном запуске или когда pipeline поставлен на паузу вручную.
Зачем это
Авто-пауза — это ограничитель радиуса поражения. Сломанный pipeline — неправильные учётные данные, несовпадение схемы коннектора, триггер, срабатывающий на плохих данных, — может пережечь вашу квоту запусков, засыпать вас уведомлениями об ошибках и накрутить расходы на внешние сервисы (токены OpenAI, доставка вебхуков, отправка email) столько, сколько расписание или вебхук будет его подбрасывать. Три страйка — и платформа останавливает кровотечение.
Это жёсткая остановка, а не повтор. После авто-паузы pipeline остаётся остановленным, пока вы его не реактивируете.
Как восстановиться
Когда pipeline на авто-паузе или запуск упал:
- Откройте детальное представление запуска для последнего сбоя. Прочитайте сообщение об ошибке на упавшем шаге. См. Отладка запусков, чтобы проследить поток данных через запуск.
- Исправьте первопричину. Обновите учётные данные, поправьте сопоставление полей, исправьте нижестоящую схему — что бы там ни было на самом деле. Повтор или реактивация без исправления просто упрутся в ту же стену.
- Повторите упавший запуск (replay), если хотите продолжить с места остановки. Replay переиспользует журнал исходного запуска, так что уже успешные шаги не выполнятся повторно — исполнитель продолжит с точки падения.
- Реактивируйте pipeline из детального представления, когда будете уверены в исправлении. Это снова включит подписки на вебхуки и расписания.
Смотрите также
- Отладка запусков — чтение журнала, поиск упавшего шага, отслеживание данных.
- Лимиты — таймаут шага (30 с), таймаут pipeline (300 с), per-user лимит запусков.
- Справочник Code Node — как ошибки из Code node попадают в отчёт.
- Сопоставление полей — как
undefined-выходы упавшего-но-продолженного шага распространяются.