【问题标题】:How to use Cadence/Temporal versioning API( workflow.getVersion) in a loop如何在循环中使用 Cadence/Temporal 版本控制 API(workflow.getVersion)
【发布时间】:2022-10-21 01:17:42
【问题描述】:

想象一下这个循环中包含 10 个活动的工作流程:

public class LoopWorkflowImpl implements LoopWorkflow{
   private final Api api = Workflow.newActivityStub(Api.class, ...)

   @override
   public int start(){
        int sum = 0;
        for(int i=0; i<10; i++){
             sum += api.getCount();
        }
        return sum;
   }
}

如何将现有工作流程的 api.getCount() 更改为 api.getCountV2()

例如。如果工作流已经使用api.getCount() 完成了 5 个活动,如何让它使用api.getCountV2() 进行其余 5 个活动?

【问题讨论】:

    标签: cadence-workflow temporal-workflow


    【解决方案1】:

    正确的方式

    这是你应该做的——在每次迭代中使用带有 changeId 的版本控制 API:

    public class LoopWorkflowImpl implements LoopWorkflow{
       private final Api api = Workflow.newActivityStub(Api.class, ...)
    
       @override
       public int start(){
            int sum = 0;
            for(int i=0; i<10; i++){
                 int version = Workflow.getVersion("useV2API"+i, Workflow.DEFAULT_VERSION, 1)
                 if( version == 1){
                     sum += api.getCountV2();
                 }else{
                     sum += api.getCount();
                 }
            }
            return sum;
       }
    }
    
    

    A Wrong way by common 错误

    许多人会这样做,它不适用于现有的工作流程

    public class LoopWorkflowImpl implements LoopWorkflow{
       private final Api api = Workflow.newActivityStub(Api.class, ...)
    
       @override
       public int start(){
            int sum = 0;
            for(int i=0; i<10; i++){
                 int version = Workflow.getVersion("useV2API", Workflow.DEFAULT_VERSION, 1)
                 if( version == 1){
                     sum += api.getCountV2();
                 }else{
                     sum += api.getCount();
                 }
            }
            return sum;
       }
    }
    
    

    为什么

    这是因为Workflow.getVersion() API 的一个重要合约——

    来自 API 的相同 changeId 的返回值在返回后是不可变的。无论是否使用 MarkerRecord 事件将版本写入历史记录,都可以保证这一点。

    所以在错误的答案中,在第一次迭代中,Workflow.getVersion() 将返回Workflow.DEFAULT_VERSION(-1),因为在回放期间没有版本标记。所以在其余的迭代中,它总是会返回Workflow.DEFAULT_VERSION

    修复的最佳方法是将迭代 Id 包含到 changeId 中。使用不同的 changeId 将允许版本控制为不同的迭代选择不同的版本。

    如果您担心这会在历史记录中创建过多的版本标记事件,您可以将此解决方案与 global versioning pattern 结合使用,以便仅对旧工作流程执行此操作:

    public class LoopWorkflowImpl implements LoopWorkflow{
       private final Api api = Workflow.newActivityStub(Api.class, ...)
       private GlovalVersionProvider globalVersionProvider = GlobalVersionProvider.get();
    
       @override
       public int start(){
            if (globalVersionProvider.isAfterVersionOfUsingGlobalVersion()) {
                GlobalVersionProvider.upsertGlobalVersionSearchAttribute();
            }
            int sum = 0;
            for(int i=0; i<10; i++){
                 if (globalVersionProvider.isAfterVersionOfUsingV2Api()) {
                     sum += api.getCountV2();
                 }else{
                     int version = Workflow.getVersion("useV2API"+i, Workflow.DEFAULT_VERSION, 1)
                    if( version == 1){
                        sum += api.getCountV2();
                    }else{
                        sum += api.getCount();
                    }
                 } 
            }
            return sum;
       }
    }
    
    

    因此,具有迭代索引的版本控制标记仅适用于现有的旧工作流执行。

    【讨论】: