如何在不破坏确定性的情况下对 Uber Cadence Workflow 进行更改或修复?

How to make changes or fixes to Uber Cadence Workflow without breaking determinism?

升级 运行 工作流程的推荐做法是什么?

如果已经有 运行 个使用以前的工作流实现创建的执行,那么进行任何代码更改或更新工作流逻辑都会导致 Cadence "Non Deterministic Error",因为它无法重播现有工作流执行的历史记录使用更新的实现。

在不破坏现有工作流执行的情况下处理升级的一些策略是什么?

GetVersion 用于安全地对工作流定义执行向后不兼容的更改。不允许在存在工作流 运行 时更新工作流代码,因为这会破坏确定性。解决方案是既有用于重放现有工作流的旧代码,也有在第一次执行时使用的新代码。 GetVersion returns maxSupported 第一次执行时的版本。此版本作为标记事件记录到工作流历史记录中。即使更改 maxSupported 版本,重放时也会返回记录的版本。 DefaultVersion 常量包含之前未版本化的代码版本。例如最初的工作流有以下代码:

err = cadence.ExecuteActivity(ctx, foo).Get(ctx, nil)

应该更新为

err = cadence.ExecuteActivity(ctx, bar).Get(ctx, nil)

执行更新的向后兼容方式是

v :=  GetVersion(ctx, "fooChange", DefaultVersion, 1)
if v  == DefaultVersion {
    err = cadence.ExecuteActivity(ctx, foo).Get(ctx, nil)
} else {
    err = cadence.ExecuteActivity(ctx, bar).Get(ctx, nil)
}

然后bar必须改成baz:

v :=  GetVersion(ctx, "fooChange", DefaultVersion, 2)
if v  == DefaultVersion {
    err = cadence.ExecuteActivity(ctx, foo).Get(ctx, nil)
} else if v == 1 {
    err = cadence.ExecuteActivity(ctx, bar).Get(ctx, nil)
} else {
    err = cadence.ExecuteActivity(ctx, baz).Get(ctx, nil)
}

稍后当没有工作流时运行 DefaultVersion 可以删除相应的分支:

v :=  GetVersion(ctx, "fooChange", 1, 2)
if v == 1 {
    err = cadence.ExecuteActivity(ctx, bar).Get(ctx, nil)
} else {
    err = cadence.ExecuteActivity(ctx, baz).Get(ctx, nil)
}

目前不支持在引入 GetVersion 调用后完全删除它的方法。即使只剩下一个分支也保留它:

GetVersion(ctx, "fooChange", 2, 2)
err = cadence.ExecuteActivity(ctx, baz).Get(ctx, nil)

这是必要的,因为 GetVersion 根据工作流历史执行版本验证,如果工作流代码与其不兼容,则决策失败。

Java有类似Workflow.getVersionAPI.