Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

RFC: First-class XState machine workflows on TanStack Workflow durability primitives

未关闭
#12 1 条评论 5 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

评估

难度
5/5
预计耗时
一周以上
新手友好度
25/100
Issue 类型
功能
描述清晰度
需要澄清
活跃度
冷清
技术栈
typescript

调研方向

首先阅读此 RFC,并检查其中提到的现有持久运行时原语:运行状态、信号、计时器、租约、步骤、持久化、重试和 tracing。将提议的第一个里程碑和验收标准与当前实现进行比较,然后确定围绕 XState actors、快照、计时器、事件和 store 支持的未解决设计问题。当形成一份达成共识的设计和一份有 review 支持的实现计划时,即可视为完成;未指定具体文件或测试。

由索引模型根据 Issue 内容生成。

描述

Summary

Add an optional, first-class machine-workflow layer for TanStack Workflow, initially centered on XState. The goal is to support workflows as data structures without replacing the existing async/await authoring model.

The durable runtime primitives stay the same: run state, events/signals, timers, leases, durable steps/checkpoints, persistence, retries, and observability. The machine layer gives users a graph-shaped workflow representation that can be annotated, analyzed, visualized, diffed, simulated, generated, and used to drive UI.

Proposed package shape:

import { defineXStateWorkflow } from '@tanstack/workflow-xstate'

export const orderWorkflow = defineXStateWorkflow({
  id: 'order',
  machine: orderMachine,
  actors: {
    chargeCard: async ({ input }) => {
      // executed durably via Workflow step/checkpoint primitives
    },
    sendReceipt: async ({ input }) => {},
  },
})

Motivation

Async/await workflows are excellent for human-authored, procedural workflows:

  • sequential orchestration
  • simple branching
  • retries
  • checkpointed side effects
  • readable TypeScript

But they are weaker as a workflow representation when users need:

  • many possible external events while a run is paused
  • UI-driven or human-driven workflow states
  • visualization
  • static analysis
  • simulation
  • diffing workflow definitions
  • AI-generated workflows
  • graph editors
  • "what events are valid right now?" tooling
  • "what states can this workflow be in?" tooling

State machines make the workflow itself inspectable. The core question is whether TanStack Workflow can run those machine definitions durably without making XState or graph workflows the foundation of the entire runtime.

Non-goals

  • Do not replace defineWorkflow or ctx.step.
  • Do not rearchitect the durable store around XState.
  • Do not require XState for users who prefer code-shaped workflows.
  • Do not treat arbitrary XState actions as safe durable side effects.
  • Do not rely on in-memory XState timers for durable workflow delays.

Proposed Architecture

TanStack Workflow should support multiple authoring models over the same durable substrate:

TanStack Workflow durable runtime
  - runs
  - event log
  - latest durable state/snapshot
  - durable step/effect results
  - timers
  - signals/events
  - leases
  - schedules
  - tracing

Async/await authoring
  - code-shaped workflows
  - replay/checkpoint-driven execution

Machine authoring
  - data-shaped workflows
  - snapshot + event transition interpreter
  - durable effects via ctx.step/checkpoints

The machine layer should be snapshot-first and event-log-backed:

  1. Load the current persisted machine snapshot for the run.
  2. Accept an incoming event/signal/timer/approval.
  3. Transition the machine from the current snapshot.
  4. Persist the new snapshot.
  5. Execute any immediately runnable invoked actors/effects through Workflow durable step primitives.
  6. Feed actor completion/error events back into the machine.
  7. Continue until the machine reaches a final state or is waiting for external input/timer work.

Normal machine execution should not need to replay the entire workflow from the beginning. The event log remains important for auditability, debugging, deterministic tests, migrations, rebuilds, and observability.

Core Durability Rule

XState may describe effects, but TanStack Workflow must execute/checkpoint them.

For example, this XState shape is fine:

invoke: {
  src: 'chargeCard',
  onDone: 'paid',
  onError: 'paymentFailed',
}

But the adapter should execute it through a durable Workflow boundary:

await ctx.step('xstate.actor.chargeCard.<stable-id>', () =>
  actors.chargeCard(args),
)

If the process crashes after the payment provider succeeds but before the machine snapshot is fully advanced, the durable step result should prevent the payment actor from being rerun.

Proposed Public API Sketch

const workflow = defineXStateWorkflow({
  id: 'order-fulfillment',
  version: '1',
  machine: orderMachine,
  actors: {
    chargeCard,
    reserveInventory,
    shipOrder,
  },
  inputToEvent: (input) => ({ type: 'ORDER_CREATED', input }),
})

Possible lower-level interpreter API:

await runXStateWorkflow(ctx, {
  machine,
  actors,
  input,
})

Potential event delivery API:

await runtime.deliverSignal({
  runId,
  name: 'xstate.event',
  payload: { type: 'APPROVE', approverId },
})

Or a typed helper:

await runtime.sendMachineEvent({
  runId,
  event: { type: 'APPROVE', approverId },
})

Possible Runtime Primitive Needed

Machine workflows often wait for one of many valid events, not one specific signal.

We should evaluate adding a primitive like:

const event = await ctx.waitForAny([
  'APPROVE',
  'REJECT',
  'CANCEL',
])

or:

const event = await ctx.waitForEvent()

For machine workflows, the valid event set can come from the machine snapshot/state. This avoids Promise.race([...all possible signals]) style workarounds.

XState Mapping

Machine states

Persist as durable machine snapshots. Prefer XState's native snapshot/persistence APIs where possible.

Events

Map Workflow signals/events/timers/approvals to XState events.

Invoked actors/services

Map to durable Workflow steps. Actor IDs must produce stable step IDs.

Guards

Should be deterministic and side-effect free. Any DB/network/time/random/AI work should be modeled as a durable actor/effect instead.

Actions

Pure actions such as assign are safe. Side-effectful actions are dangerous unless explicitly routed through Workflow durable effects. Docs should strongly recommend keeping XState actions pure.

Delays / after

Must map to Workflow durable timers. Do not rely on in-memory timers.

Final states

Map to Workflow run completion.

Errors

Actor errors should become XState error events and also use Workflow's failure/retry semantics where configured.

Persistence Model

A machine workflow likely needs to persist:

  • current XState snapshot
  • accepted event log
  • durable actor/effect results
  • timers scheduled from delayed transitions
  • run metadata/status

Open question: should the machine snapshot be stored in the existing run state/events model, or does the durable store contract need explicit machine snapshot methods?

A plausible first version can store the machine snapshot as part of workflow run state without requiring new top-level store primitives, then promote schema/store APIs if dogfooding shows pressure.

Observability

The existing Workflow OTel tracing should naturally wrap machine runs:

  • runtime operations
  • store boundaries
  • drive run
  • durable actor/step execution

Machine-specific attributes/events could include:

  • tanstack.workflow.machine.id
  • tanstack.workflow.machine.state
  • tanstack.workflow.machine.event_type
  • tanstack.workflow.machine.actor_id

Need to preserve the same privacy posture: no event payloads, workflow input, actor result, or context payload values in attributes by default.

Example Dogfood Scenario

Build a demo workflow that benefits from being graph-shaped:

  • order approval or content publishing workflow
  • starts from input
  • waits for any of several events: approve, reject, request changes, cancel
  • has at least one durable actor invocation
  • has at least one durable timer / timeout transition
  • can render a visualization from the same machine definition
  • can expose valid next events to UI
  • can resume from a persisted snapshot without replaying all prior events

This should be a serious demo, not a toy counter.

Open Questions

  1. What exact XState v5 APIs should we lean on for snapshot persistence, hydration, actors, and inspection?
  2. Can invoked actors be cleanly intercepted/executed by Workflow without fighting XState internals?
  3. How should durable timers map to XState after transitions?
  4. Should Workflow expose a generic waitForAny / waitForEvent primitive independent of XState?
  5. Are side-effectful XState actions forbidden, warned against, or supported through a special adapter API?
  6. How do we produce stable step IDs for actors across machine edits?
  7. How should versioning/migrations work when the machine graph changes while runs are in flight?
  8. Should machine snapshots live in existing run-state persistence or get explicit store contract support?
  9. How much type inference can we preserve from XState events/context/actors through the Workflow adapter?
  10. Should this start as @tanstack/workflow-xstate experimental, or live in core behind optional peer dependency boundaries?

Proposed First Milestone

Ship an experimental @tanstack/workflow-xstate package that proves:

  • an XState machine can be run as a TanStack Workflow
  • current machine snapshot is persisted and resumed
  • external events wake and transition the machine
  • invoked actors execute through durable Workflow steps
  • replay/wake-up does not rerun completed actors
  • delayed transitions use durable Workflow timers
  • final states complete the Workflow run
  • docs clearly explain pure transitions/actions vs durable effects

Acceptance Criteria

  • Users can bring an XState machine and run it on TanStack Workflow durability primitives.
  • The adapter does not require apps to abandon existing async/await workflows.
  • Durable side effects remain checkpointed by Workflow.
  • Machine workflows can expose valid next events/state for UI/tooling.
  • The implementation avoids payload/result/context leakage in telemetry by default.
  • The design has review from people familiar with XState/statecharts and durable execution tradeoffs.

Review Request

Would love review especially from folks with XState/statechart experience and folks building long-lived human/event-driven workflows.

Specific feedback wanted:

  • Is this the right boundary between XState and TanStack Workflow?
  • Which XState concepts map cleanly, and which ones should we intentionally not support at first?
  • Is snapshot-first, event-log-backed durability the right model?
  • What awkward cases would make this adapter frustrating in real apps?
  • What demo would prove this is actually useful?
主要语言
TypeScript
星标
221
派生
10
PR 合并指标
30 天内没有已合并 PR

环境准备

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

TanStack/workflow 的其他 Issue

查看 TanStack/workflow 的全部 Issue

相似的 Issue

更多 TypeScript Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。