Перейти к содержимому

Создание управляемого рабочего процесса (DAG)

Рабочий процесс связывает действия, которыми платформа уже управляет: срабатывание расписания, отправку сигналов другим модулям, тестовое уведомление, ожидание — в граф зависимостей (DAG). Его запуск является единым привилегированным действием, согласованным человеком, а каждый шаг, который на что-либо воздействует, оставляет строку в том же append-only журнале решений, что и однократное срабатывание расписания.

Рабочие процессы — это композиция, а не новая власть. Намеренно нет вида шага, который выполняет команду, обращается к произвольному URL или несёт payload: граф может только переставлять уже доступные estate действия под уже существующими гейтами. Для запуска нужен уровень администратора и человеческое согласование, поэтому рабочий процесс никогда не даёт доступа к тому, к чему нельзя обратиться напрямую.

Рабочий процесс — набор шагов. У каждого есть короткий уникальный в этом процессе ref, kind, типизированный config и ссылки в depends_on. Граф должен быть ациклическим; сервер проверяет это, существование ссылок и границы fan-in/fan-out до сохранения каких-либо данных.

ВидДействиеПроходимые гейты
schedule-fireзапускает существующее управляемое расписаниеkill switch, бюджет, dispatcher seam
eventing-emitпубликует событие workflow.signal, на которое могут подписаться другие модули
notify-testотправляет синтетический тест через маршрут оповещенияseam актуатора уведомлений
waitприостанавливает выполнение на ограниченное время (1 с–24 ч)
approval-gateоткрывает человеческое согласование в середине графа и ждёт решениягейт согласования

eventing-emit публикует фиксированный тип события. Конфигурация шага добавляет только метку, поэтому автор рабочего процесса не может подделать first-party событие вроде edge.observed и направить его в ingest другого модуля.

Окно терминала
curl -sS -X POST "$OLIVARES/v1/m/orchestration/workflows" \
-H "Authorization: Bearer $TOKEN" -H "X-Olivares-Tenant: $TENANT" \
-H 'Content-Type: application/json' -d '{
"name": "release-train",
"steps": [
{"ref":"announce","kind":"eventing-emit","config":{"label":"starting"},"depends_on":[]},
{"ref":"hold","kind":"approval-gate","config":{"reason":"release window"},"depends_on":["announce"]},
{"ref":"deploy","kind":"schedule-fire","config":{"schedule_id":"<id>"},"depends_on":["hold"]}
]}'

Создание требует write-tier. Отклонённый граф возвращает 400 с указанием ошибочного шага:

{"error":{"message":"step deploy: schedule <id> is retired","step_ref":"deploy"}}

Консоль привязывает этот step_ref к узлу на холсте. Последующая замена графа — единый атомарный PUT .../steps: граф проверяется и согласовывается целиком, а не по шагам.

Каждое изменение дописывает полный снимок в журнал ревизий. Любую прежнюю ревизию можно восстановить с той же проверкой, которую используют live-действия.

Окно терминала
curl -sS -X POST "$OLIVARES/v1/m/orchestration/workflows/$ID/dry-run" \
-H "Authorization: Bearer $TOKEN" -H "X-Olivares-Tenant: $TENANT"

Dry-run возвращает шаги в топологическом порядке, описывает действие и проходимые гейты каждого из них и предупреждает, если ссылка устарела после сохранения графа (например, расписание было выведено из эксплуатации на прошлой неделе). Он ничего не записывает, ничего не запускает и не открывает согласование, поэтому это чтение, доступное всем, кто может читать рабочие процессы.

Он также возвращает plan_hash — отпечаток точного графа. Это понадобится далее.

3. Запустите — в две фазы, с привязкой к увиденному человеком

Заголовок раздела «3. Запустите — в две фазы, с привязкой к увиденному человеком»

Запуск требует уровня администратора и проходит гейт. Первая фаза открывает согласование:

Окно терминала
curl -sS -X POST "$OLIVARES/v1/m/orchestration/workflows/$ID/run" \
-H "Authorization: Bearer $TOKEN" -H "X-Olivares-Tenant: $TENANT"
# 202 {"op":"run_request","approval_ref":"…","gate_status":"pending", …}

Человек принимает решение через API governance-решений. Затем вторая фаза потребляет решение: его ссылку передают обратно.

Окно терминала
curl -sS -X POST "$OLIVARES/v1/m/orchestration/workflows/$ID/run" \
-H "Authorization: Bearer $TOKEN" -H "X-Olivares-Tenant: $TENANT" \
-H 'Content-Type: application/json' -d '{"approval_ref":"…"}'

Согласование привязано к хешу плана. Если между фазами изменить граф, хеш изменится, согласование больше ничего не авторизует и запуск будет отклонён. Человеческое «да» относится к проверенному графу, но никогда не к подменённому после проверки. Затем выполняется снимок этого графа, поэтому изменение во время запуска не может повлиять на уже выполняемую работу.

Deny-by-default действует постоянно: если гейт согласования не подключён, запуск отклоняется, а пробел в governance поднимается как находка, а не молча разрешается.

Окно терминала
curl -sS "$OLIVARES/v1/m/orchestration/workflows/$ID/runs/$RUN" \
-H "Authorization: Bearer $TOKEN" -H "X-Olivares-Tenant: $TENANT"

Каждый шаг сообщает собственное состояние. Если вышестоящий шаг завершился с ошибкой, зависимый шаг получает skipped: процесс никогда не продолжает работу после ошибки и не сообщает об успехе, которого не было. wait показывает время возобновления, а approval-gate — ожидаемое согласование. При аварийной остановке весь процесс замораживается с видимым paused_reason и возобновляется после снятия остановки. Остановка никогда не поглощается молча и сама по себе никогда не завершает процесс ошибкой.

Шаги продвигаются фоновым обработчиком, поэтому ожидания и согласования в середине графа продолжаются без необходимости держать запрос открытым.

Каждый актуирующий шаг дописывает неизменяемую строку, приписанную человеку, который начал выполнение. Важны два свойства:

  • Отклонённый запуск также записывается. Отказы — это доказательства.
  • Если результат актуации приходит после того, как runner уже перестал его ждать, результат сверяется с реальной ссылкой dispatch и записывается в журнал. Шаг может показывать «результат неизвестен», но журнал никогда не утверждает, что произошла несуществующая актуация, и не скрывает реально произошедшую.
  • Автоматические триггеры. Рабочий процесс запускается после человеческого согласования. Подключение cron или события для начала выполнения создаёт путь автоматической актуации без оператора и должно появиться отдельным изменением за существующим контуром расписаний.
  • Шаги с произвольными побочными эффектами (HTTP, exec). Они превратили бы поверхность композиции в универсальный движок выполнения и нарушили бы свойство, по которому рабочий процесс может только переставлять уже управляемые действия.