Cadence工作流必须是确定性的,这意味着如果使用相同的输入参数执行工作流,则预期会产生完全相同的结果。
当我以新的Cadence用户身份了解了以上要求时,我想知道当需要确定性突破性的更改时,如何长期维护工作流程。
一个示例场景是,您有一个工作流连续执行Activity1和Activity2,然后您需要更改这些活动的顺序,以便工作流在Activtiy1之前执行Activity2。还有许多其他方法可以进行类似确定性的更改,我想了解如何处理这些更改。
在工作流可以长时间运行(例如几天,几周甚至几个月)的情况下,这尤其重要!
答案 0 :(得分:1)
显然,这可能是新的Cadence开发人员提出的最常见问题之一。 Cadence工作流程必须为deterministic algorithms。如果工作流算法不确定,则Cadence工作人员在尝试重播历史记录时(例如,在工作人员故障恢复期间)将有遇到不确定工作流错误的风险。
有两种方法可以解决此问题:
下面是基于GetVersion()的方法的示例。假设您要在工作流程中更改以下行:
err = workflow.ExecuteActivity(ctx, foo).Get(ctx, nil)
到
err = workflow.ExecuteActivity(ctx, bar).Get(ctx, nil)
这是一项重大更改,因为它运行 bar 活动而不是 foo 。如果您只是进行更改而不必担心确定性,那么您的工作流将无法重播,并且会出现不确定性工作流错误。正确进行此更改的正确方法是按如下方式更新工作流程:
v := GetVersion(ctx, "fooChange", DefaultVersion, 1)
if v == DefaultVersion {
err = workflow.ExecuteActivity(ctx, foo).Get(ctx, nil)
} else {
err = workflow.ExecuteActivity(ctx, bar).Get(ctx, nil)
}
GetVersion函数接受4个参数:
当此工作流程的新实例首次到达上面的GetVersion()调用时,该函数将返回 maxSupportedVersion 参数,以便您可以运行最新版本的工作流程算法。同时,它还将在工作流程历史记录中记录该版本号(内部称为“ 标记事件”),以便将来使用。稍后重播此工作流时,即使您传递了不同的 maxSupportedVersion 参数(即,如果您的工作流有更多版本),Cadence客户端也将继续返回相同的版本号。
如果在历史记录重播期间遇到GetVersion调用,并且该历史记录没有先前记录的标记事件,则该函数将返回 DefaultVersion ,并假定“ fooChange” 在此工作流实例的上下文中从未存在。
如果您需要在工作流的同一步骤中再做一次重大更改,只需更改上面的代码,如下所示:
v := GetVersion(ctx, "fooChange", DefaultVersion, 2) // Note the new max version
if v == DefaultVersion {
err = workflow.ExecuteActivity(ctx, foo).Get(ctx, nil)
} else if v == 1 {
err = workflow.ExecuteActivity(ctx, bar).Get(ctx, nil)
} else { // This is the Version 2 logic
err = workflow.ExecuteActivity(ctx, baz).Get(ctx, nil)
}
如果您愿意放弃对版本0 的支持,则可以像上面那样更改上面的代码:
v := GetVersion(ctx, "fooChange", 1, 2) // DefaultVersion is no longer supported
if v == 1 {
err = workflow.ExecuteActivity(ctx, bar).Get(ctx, nil)
} else {
err = workflow.ExecuteActivity(ctx, baz).Get(ctx, nil)
}
此更改之后,如果您的工作流代码针对具有 DefaultVersion 版本的旧工作流实例运行,则Cadence客户端将引发错误并停止执行。
最终,您可能希望摆脱所有以前的版本,而仅支持最新版本。一种选择是简单地完全摆脱GetVersion调用和if语句,而只用一行代码来完成正确的事情。但是,将GetVersion()调用保留在其中实际上是一个更好的主意,这有两个原因:
考虑到上述两个原因,当您应该放弃对所有旧版本的支持时,您应该像下面那样更新工作流代码:
GetVersion(ctx, "fooChange", 2, 2) // This acts like an assertion to give you a proper error
err = workflow.ExecuteActivity(ctx, baz).Get(ctx, nil)