Skip to main content

Module workflow

Module workflow 

Source
Expand description

workflow 模式:把事务流程写成一个普通函数,崩溃后从断点续跑。

§跟前四种模式的差别

SAGA / TCC / msg / XA 都要求提交时就把步骤声明清楚。真实业务经常不满足: 第三步做不做取决于第二步返回了什么,中间还有 if、有循环。

workflow 模式让你直接写:

tc.workflow("下单", |mut wf| async move {
    let oid = wf.branch("建订单").on_rollback("local://取消订单")
        .run_with(|| async { (BranchResult::Success, new_order_id()) }).await?;

    wf.branch("扣款").on_rollback("local://退款")
        .run(|| async { deduct(&oid).await }).await?;

    // 控制流是真的控制流
    if need_ship(&oid) {
        wf.branch("发货").on_rollback("local://退货")
            .run(|| async { ship(&oid).await }).await?;
    }
    Ok(())
})

§崩溃恢复靠重放 + 结果记忆化

进程崩了重启,TC 会把这个函数从头再跑一遍。已经成功过的分支不重新执行, 而是把上次存的返回值原样还给你 —— 所以函数会沿着上次的路径走到断点, 然后继续往下。

第一次:  建订单(真跑,存 oid) → 扣款(真跑) → 崩溃
重启后:  建订单(记忆化,还回 oid) → 扣款(记忆化) → 发货(真跑) → 完成
                   ↑ 副作用不会重做

§⚠ 你的函数必须是确定性的

重放是从头再跑,所以分支之间的那些代码会被执行多次。它们必须在相同的 分支返回值下走相同的路径:

  • if rand() > 0.5if now().hour() < 12、读一个会变的全局状态
  • ❌ 在分支外面直接写数据库 —— 那部分不会被记忆化,重放时会重复执行
  • ✅ 所有副作用都放进 branch(...).run(...)

写岔了会怎样?本模块会当场发现并拒绝继续(见 WorkflowError::Diverged), 而不是静默补偿错对象。这是刻意的:静默走错比停下来严重得多。

§为什么这个模式只在嵌入式形态下提供

因为「步骤」是代码,没法表示成一个 URL 存进数据库。DTM 那边也是同理: workflow 的函数体在客户端进程里,TC 只存状态。 我们把 TC 也放在同一个进程里,所以这件事反而更自然。

Structs§

BranchBuilder
WorkflowCtx
传给 workflow 函数的上下文。分支都从这里开。
WorkflowRegistry
按名字存 workflow 函数。

Enums§

WorkflowError
函数跑不下去的原因。用 ? 往外抛。

Type Aliases§

WorkflowResult