如何在不破坏确定性的前提下对Uber Cadence Workflow进行更改或修复? [英] How to make changes or fixes to Uber Cadence Workflow without breaking determinism?

查看:519
本文介绍了如何在不破坏确定性的前提下对Uber Cadence Workflow进行更改或修复?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

如果已经有使用先前的工作流程实现创建的正在运行的执行,则进行任何代码更改或更新工作流程逻辑都会导致Cadence出现非确定性错误",因为它无法使用更新的实现来重放现有工作流程执行的历史记录. >

在不中断现有工作流程执行的情况下,有哪些应对升级的策略?

解决方案

GetVersion 用于安全地对工作流程定义执行向后不兼容的更改.在有工作流运行时,不允许更新工作流代码,因为这将破坏确定性.解决方案是既有用于重播现有工作流程的旧代码,又有第一次执行时使用的新代码.第一次执行时,GetVersion返回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)
}

然后必须将栏更改为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具有类似的

What are some strategies to deal with upgrades without breaking existing workflow executions?

GetVersion is used to safely perform backwards incompatible changes to workflow definitions. It is not allowed to update workflow code while there are workflows running as it is going to break determinism. The solution is to have both old code that is used to replay existing workflows as well as the new one that is used when it is executed for the first time. GetVersion returns maxSupported version when is executed for the first time. This version is recorded into the workflow history as a marker event. Even if maxSupported version is changed the version that was recorded is returned on replay. DefaultVersion constant contains version of code that wasn't versioned before. For example initially workflow has the following code:

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

it should be updated to

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

The backwards compatible way to execute the update is

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)
}

Then bar has to be changed to 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)
}

Later when there are no workflows running DefaultVersion the correspondent branch can be removed:

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)
}

Currently there is no supported way to completely remove GetVersion call after it was introduced. Keep it even if single branch is left:

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

It is necessary as GetVersion performs validation of a version against a workflow history and fails decisions if a workflow code is not compatible with it.

The Java has similar Workflow.getVersion API.

这篇关于如何在不破坏确定性的前提下对Uber Cadence Workflow进行更改或修复?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆