Skip to content

Когда нужна оркестрация

Оркестрация нужна, когда одна пользовательская операция состоит из нескольких асинхронных шагов с зависимостями.

Пример оформления заказа:

  1. получить актуальную корзину;
  2. параллельно получить адрес и способы оплаты;
  3. зарезервировать товар;
  4. провести платёж;
  5. если платёж упал — снять резерв.

WorkflowStore управляет порядком, прогрессом, отменой, checkpoint и компенсацией.

Что WorkflowStore не делает

WorkflowStore не должен выполнять Axios напрямую. Каждый node вызывает уже готовый domain store:

ts
const workflow = new WorkflowStore({
  nodes: [
    {
      id: "profile",
      execute: async () => profileStore.fetch(),
    },
  ],
})

Так loading, error normalization, cache и cancellation HTTP-операции остаются в Query Layer stores.

Когда workflow не нужен

Не создавайте workflow для одного запроса:

ts
await profileStore.fetch()

Обычный async method также понятнее для двух строго последовательных операций без progress, retry recovery и compensation.

Workflow оправдан, если нужны несколько пунктов:

  • граф зависимостей;
  • параллельные независимые шаги;
  • условные nodes;
  • общий observable progress;
  • отмена всей операции;
  • compensation уже выполненных шагов;
  • восстановление после reload.

Основные понятия

ТерминЗначение
WorkflowВся составная операция.
NodeОдин именованный шаг.
DependencyNode, который должен завершиться раньше.
Execution levelНезависимые nodes, которые можно запустить параллельно.
ResultЗначение, возвращённое node.
ConditionУсловие, может ли node выполняться.
CompensationОбратное действие после ошибки следующего шага.
CheckpointСохранённые completed node ids и serializable results.

Простейший workflow

ts
import { WorkflowStore } from "@dubium/query-layer/orchestration"

const bootstrapWorkflow = new WorkflowStore({
  nodes: [
    {
      // Уникальное имя результата.
      id: "profile",

      // Node вызывает domain store, а не Axios.
      execute: async () => profileStore.fetch(),
    },
    {
      id: "permissions",
      execute: async () => permissionsStore.fetch(),
    },
  ],

  // Одновременно работает не больше двух nodes.
  concurrency: 2,
})

const results = await bootstrapWorkflow.execute()

const profile = results.get("profile")
const permissions = results.get("permissions")

У nodes нет dependencies, поэтому они находятся на одном execution level и могут выполняться параллельно.

Observable state

ts
workflow.status
// idle | running | success | error | cancelled

workflow.progress
// { nodeId, status, completed, total } | null

workflow.results
// ReadonlyMap<string, unknown>

workflow.error
// unknown

WorkflowStore сам является MobX-store. React-компонент оборачивается в observer и читает эти поля.

Порядок изучения

  1. WorkflowStore — полный пример и API.
  2. Узлы и зависимости — DAG, conditions, results.
  3. Ошибки и компенсация — rollback составной операции.
  4. Checkpoint — восстановление после reload.
  5. React и тестирование — UI progress и tests.