【问题标题】:What exactly is a Cadence decision task?Cadence 决策任务到底是什么?
【发布时间】:2020-11-04 07:37:46
【问题描述】:

活动任务很容易理解,因为它正在执行一项活动……但什么是决策任务?工作人员是否从头开始运行工作流(使用已完成活动的记录),直到遇到下一个需要做的“有意义”的事情,同时对下一步需要做的事情做出“决定”?

【问题讨论】:

    标签: cadence-workflow temporal-workflow


    【解决方案1】:

    TL;DR

    Decision 是 workflow decision 的缩写。

    决策是工作流状态机中从一种状态到另一种状态的移动。本质上,您的工作流代码定义了一个状态机。此状态机必须是 deterministic state machine 才能重播,因此工作流代码必须是确定性的。

    决策任务是工作人员执行工作流代码以生成决策的任务。

    示例

    假设我们有这个工作流代码:

    public string sampleWorkflowMethod(...){
      var result = activityStubs.activityA(...)
      if(result.startsWith("x"){
         Workflow.sleep(...)
      }else{
         result = activityStubs.activityB(...)
      }
      
      return result
    }
    

    从 Cadence SDK 的角度来看,代码是一个状态机。

    假设我们有一个执行,activityA的结果是xyz,那么执行就会进入sleep分支。

    那么工作流执行流程就是这个图。

    • 工作流代码定义状态机,它是静态的。
    • 工作流执行将根据输入/结果/和代码逻辑决定如何在运行时从一种状态移动到另一种状态
    • Decision 是 Cadence 内部的抽象。在工作流执行期间,当它从一种状态变为另一种状态时,决定就是该运动的结果。
    • 抽象基本上是定义当执行从一种状态转移到另一种状态时需要做什么——调度活动、计时器或子WF等。
    • 决策需要是确定性的 --- 使用相同的输入/结果,工作流代码应该做出相同的决定 --- 调度活动 A 或 B 必须相同。

    示例中的时间轴

    在上述工作流程执行期间会发生什么

    1. Cadence 服务安排非常第一个决策任务,分派给工作流工作者
    2. worker执行第一个决策任务,并将调度activityA的决策结果返回给Cadence服务。然后工作流就在那里等待。
    3. 作为调度 activityA 的结果,Cadence 服务会生成一个活动任务,并将该任务分派给一个活动工作者
    4. 活动工作者执行活动并将结果xyz返回给Cadence服务。
    5. Cadence 服务收到活动结果后,会安排第二个决策任务,并分派给工作流工作者。
    6. 工作流工作者执行第二个决策任务,并将调度计时器的决策结果响应给Cadence服务
    7. 收到决策任务响应后,Cadence 服务会安排一个计时器
    8. 当计时器触发时,Cadence 服务会安排第三个决策任务并再次分派给工作流工作者
    9. 工作流工作者执行第三个决策任务,并以结果xyz响应成功完成工作流执行的结果。

    关于决策的更多事实

    • 工作流决策是协调那些其他实体,如活动/ChildWorkflow/Timer/等。

    • Decision(workflow) 任务是与 Cadence 服务通信,告诉下一步要做什么。例如,开始/取消一些活动,或完成/失败/continueAsNew 一个工作流。

    • 对于每个工作流执行,总是最多有一个未完成(运行/待定)的决策任务。一个已经开始但还没有完成的时候,不可能开始一个。

    • 在编写 Cadence 工作流程时,决策任务的性质会导致一些不确定性问题。更多详情可以参考article

    • 在每个决策任务上,Cadence Client SDK 可以从头开始“重播”代码,例如,执行 activityA。但是,这种重放模式不会再次产生调度activityA的决定。因为客户端知道activityA已经安排好了。

    • 但是,工作人员不必从一开始就运行代码。 Cadence SDK 足够智能,可以将状态保存在内存中,稍后唤醒以继续之前的状态。这称为“工作流粘性缓存”,因为工作流在工作主机上会保持一段时间的粘性。

    例子的历史事件:

    1. WorkflowStarted
    2. DecisionTaskScheduled
    3. DecisionTaskStarted
    4. DecisionTaskCompleted
    5. ActivityTaskScheduled <this schedules activityA>
    6. ActivityTaskStarted
    7. ActivityTaskCompleted <this records the results of activityA>
    8. DecisionTaskScheduled
    9. DecisionTaskStarted
    10. DecisionTaskCompleted
    11. TimerStarted         < this schedules the timer>
    12. TimerFired
    13. DecisionTaskScheduled
    14. DecisionTaskStarted
    15. DecisionTaskCompleted
    16. WorkflowCompleted
    

    【讨论】:

      【解决方案2】:

      TLDR;当接收到新的外部事件时,工作流任务负责确定接下来要执行哪些命令。

      Temporal/Cadence 工作流程由外部工作人员执行。因此,了解工作流必须采取的后续步骤的唯一方法是在每次有新信息可用时询问它。将此类请求分派给工作人员的唯一方法是将工作流任务放入任务队列中。工作流工作者将其拾取,从其缓存中取出工作流,并将新事件应用到它。应用新事件后,工作流执行生成一组新命令。在工作流代码被阻止并且无法进行任何向前进展后,工作流任务将报告为已完成返回给服务。要执行的命令列表包含在完成请求中。

      工作人员是否从头开始运行工作流(使用已完成活动的记录),直到遇到下一个需要做的“有意义”的事情,同时对下一步需要做的事情做出“决定”?

      这取决于工作人员是否在其 LRU 缓存中具有工作流对象。如果工作流在缓存中,则不需要恢复,工作流任务中只包含新事件。如果对象没有被缓存,那么整个事件历史都会被发送,并且工作人员必须从一开始就执行工作流代码以将其恢复到当前状态。回放过去事件时生成的所有命令都是先前生成的命令的副本,并且会被忽略。

      以上意味着在工作流的生命周期内必须执行多个工作流任务。例如,对于按顺序调用两个活动的工作流:

      a();
      b();
      

      任务将在每次状态转换时执行:

      -> workflow task at the beginning: command is ScheduleActivity "a"
          a();
      -> workflow task when "a" completes: command is ScheduleActivity "b"
          b();
      -> workflow task when "b" completes: command is CompleteWorkflowExecution
      

      在答案中,我使用了 Cadence 的 temporal.io fork 采用的术语。以下是 Cadence 概念映射到 Temporal 概念的方式:

      • 决策任务 -> 工作流任务
      • decision -> command,但在某些情况下也可以表示工作流程任务
      • 任务列表->任务队列

      【讨论】:

      • 谢谢!这很有帮助。感谢您在此 Maxim 上所做的工作
      猜你喜欢
      • 2021-11-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-15
      • 2022-06-11
      • 2013-07-02
      相关资源
      最近更新 更多