Skip to content

WorkflowStore

WorkflowStore — MobX-store состояния составной операции. Создание:

ts
new WorkflowStore(options)

Factory-функции нет.

Пример: bootstrap кабинета

Профиль и permissions независимы и загружаются параллельно. Dashboard settings можно запросить только после permissions.

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

import type { PermissionsStore } from "../../permissions/model"
import type { ProfileStore } from "../../profile/model"
import type { SettingsStore } from "../../settings/model"

export class DashboardBootstrapStore {
    // WorkflowStore координирует domain stores.
    private readonly workflow: WorkflowStore

    constructor(profileStore: ProfileStore, permissionsStore: PermissionsStore, settingsStore: SettingsStore) {
        this.workflow = new WorkflowStore({
            // На одном execution level не больше двух параллельных nodes.
            concurrency: 2,

            nodes: [
                {
                    id: "profile",

                    // ProfileStore внутри использует RequestStore/FetchStore.
                    execute: async () => profileStore.fetch(),
                },
                {
                    id: "permissions",
                    execute: async () => permissionsStore.fetch(),
                },
                {
                    id: "settings",

                    // Этот node стартует только после permissions.
                    dependencies: ["permissions"],

                    // results содержит значения completed dependencies.
                    execute: async ({ results }) => {
                        const permissions = results.get("permissions") as string[]

                        return settingsStore.fetch({
                            includeAdmin: permissions.includes("admin"),
                        })
                    },
                },
            ],
        })

        makeAutoObservable<this, "workflow">(
            this,
            {
                // Вложенный WorkflowStore уже observable.
                workflow: false,
            },
            {
                autoBind: true,
            },
        )
    }

    get running(): boolean {
        return this.workflow.status === "running"
    }

    get status(): string {
        return this.workflow.status
    }

    get completedSteps(): number {
        return this.workflow.progress?.completed ?? 0
    }

    get totalSteps(): number {
        return this.workflow.progress?.total ?? 3
    }

    get error(): unknown {
        return this.workflow.error
    }

    async initialize(): Promise<void> {
        // Каждый execute отменяет предыдущий активный запуск этого WorkflowStore.
        await this.workflow.execute()
    }

    cancel(): void {
        this.workflow.cancel()
    }

    dispose(): void {
        this.workflow.dispose()
    }
}

Конфигурация

OptionTypeDefaultЧто делает
nodesreadonly IWorkflowNode[]Обязательный список шагов.
concurrencynumberбез ограничения уровняМаксимальное число nodes одного level, выполняемых одновременно. Минимум 1.
persisterIWorkflowPersisterAdapter checkpoint storage.
workflowIdstringСтабильный id checkpoint. Обязателен вместе с persister.
now() => numberDate.nowИсточник времени snapshot, обычно для тестов.

Состояние

ПолеTypeЧто означает
statusidle | running | success | error | cancelledСостояние последнего запуска.
progressWorkflowProgressEvent | nullПоследнее событие конкретного node.
resultsReadonlyMap<string, unknown>Результаты последнего успешного workflow.
errorunknownОшибка последнего неуспешного запуска.

Во время нового запуска error очищается, но results предыдущего успеха остаются до нового success. Если UI не должен показывать старые данные, domain store должен учитывать status === "running".

Методы

МетодВозвращаетЧто делает
execute()Promise<ReadonlyMap<string, unknown>>Отменяет предыдущий запуск и выполняет workflow.
cancel()voidAbort текущего workflow. Уже завершённые nodes могут быть компенсированы.
dispose()voidОтменяет текущий запуск и освобождает controller.

У WorkflowStore нет reset(). Если нужен новый независимый lifecycle, создайте новый instance или скройте отображение старого результата в domain getters.

Progress event

ts
interface WorkflowProgressEvent {
    nodeId: string
    status: "running" | "success" | "error" | "skipped"
    completed: number
    total: number
}

progress хранит последнее событие, а не массив всей истории. Для audit log собирайте события на уровне приложения или logger.

Следующая страница: узлы и зависимости.