temporality
Изменить страницу↗
Инженерные документы

Dev-стек: живучесть ранов при пересборках

#1. Инцидент 2026-10-26 (симптом «ход вешается до таймаута»)

Пересборка стека (docker compose up --build) посреди выполняющегося рана приводила к следующей цепочке:

  1. SIGTERM ядру → активность kernel.run_tool умирает посреди команды (tool.started в журнале есть, завершения — нет);
  2. контейнер temporalio/temporal пересоздаётся — а он работал с персистентностью in-memory (server start-dev без --db-filename) — история workflow не переживает перезапуск контейнера;
  3. workspace_run.status остаётся started навсегда: в UI ход выглядит вечно выполняющимся, финального события не будет никогда;
  4. сверка операции (operation.reconciled) в этой ситуации бессмысленна — она только фиксирует вердикт в журнале и никогда не трогает workflow. Сверка в инциденте была реакцией на зависание, а не причиной.

#2. Что сделано

#2.1. Персистентность Temporal (docker-compose.yml)

temporal server start-dev --db-filename /data/temporal-dev.db + volume temporality-temporal: история workflow переживает рестарты и пересборки контейнера. In-memory остаётся только в transient-окружениях без volume.

#2.2. Orphan sweep (cmd/agent-kernel/orphansweep.go)

На старте ядра (асинхронно, не блокирует подъём) свип сравнивает:

Ран без живого workflow и без терминального события помечается failed (UpdateRunStatus) и получает честное журнальное событие run.failed (data.orphaned = true, причина в error) — UI перестаёт показывать призрак, трейл остаётся аудируемым.

Правила безопасности свипа:

#3. Эксплуатация