跳到主要内容

Step 基础功能

本页介绍 Step 的默认形态:typed input、可选的 WaitFor、必需的 Execute、通过 StepDecision 做 movement,以及默认 StepOptions 行为。

Dex Step 由原生代码实现。实现该 Step 的 struct 或 class 决定 StepType。在大多数语言里,SDK 默认从原生类型名推导 StepType;你也可以显式覆盖。

同一个 Step type 可以在同一个 Flow 中执行多次。每次执行都是一个 StepExecution,对应一个 StepExecutionID,格式是 StepType-Number,由 Dex 分配并维护。

Step input

起始 Step 接收 Flow input。之后每个 Step 接收调度它的 movement 带来的 input。Step input 随图传递,不是隐藏的全局变量。

def execute(self, context: Context, input: int) -> StepDecision:
return go_to(StepSecond, input + 1)

def execute(self, context: Context, input: int) -> StepDecision:
return graceful_complete(input + 1)

例子: examples/python/dex_examples/primitives/step/step_flow.py

WaitFor and Execute

Step implementation 通常只有一个或两个小方法:WaitFor -> Execute

WaitFor 是可选的。它向 Dex Server 返回 durable Wait。Dex 持久化该 waiting state,代表应用持续评估这些条件;条件满足后再调用 Execute

如果 Step 没有实现 WaitFor,则会直接调用 Execute

Execute 是必需的。它返回 StepDecision,用于流转到下一个 Step、分支到多个 Step,或关闭 Flow。

每次 WaitForExecute 调用都有独立的 commit 边界。Dex Server 会暂存该 method 内的 Attribute 写入和 Channel publish,并只在 method 成功返回时,将它们与相应的 WaitStepDecision 一起 commit。如果 method 失败,这些 durable 变更都不会被 commit。WaitForExecute 不共享一次 commit,外部 API 调用也不在这个原子边界内。

在最终 WaitStepDecision 之前,handler 可以发送 heartbeat checkpoint 和任意多条 best-effort Stream message。Response stream 必须以且仅以一个最终 result 结束。这些 progress frame 不属于 method commit,Stream Store 写入失败也不会让 Step 失败。

approval = Channel("Approval", str)


class StepSecond(Step[int]):
def execute(self, context: Context, input: int) -> StepDecision:
return graceful_complete(input + 1)


class ExampleStep(Step[int]):
def __init__(self, second: StepSecond) -> None:
self.second = second

def wait_for(self, context: Context, input: int) -> Wait:
return Wait.until(approval.for_one())

def execute(self, context: Context, input: int) -> StepDecision:
return go_to(StepSecond, input + 1)

例子: examples/python/dex_examples/primitives/step/step_flow.py

UntilAnyOfAllOf 接受没有 condition ID 的 Condition。不要仅仅因为 Condition 嵌套在这些等待组合中就为它添加 ID。AnyCombinationOf 是例外:其中引用的 每个 Condition 都需要唯一的 condition ID。

Step 可等待的 Condition 见 TimerChannelSubFlow

StepDecision(movement)

Execute 返回 StepDecision——指向一个或多个后续 Step 的 movement,或关闭决策。一次决策可指向多个 Step,用于表达分支、循环与并行。

并行 Step并行 SubFlow 模式。

关闭决策、取消、Flow 输出与 forceCompleteIfChannelsEmpty 见 Step decision。超时、retry 及相关策略的自定义见 Step options

StepOptions

大多数时候,需要自定义 failure handling —— timeout、retry 与 failure policy。还有 heartbeat、durability 等更高级的 Step options

  • Timeout 自定义一次方法(WaitFor/Execute)调用 attempt 的 timeout。
  • Retry policy — 在同一 Step execution 上重复调用同一方法,直到 attempt 耗尽。
  • Failure policy — 决定 retry 结束之后发生什么。默认失败 Flow,但 WaitFor 仍可运行 Execute,Execute 也可以前往 recovery Step。

通过在 Step 方法中实现返回 StepOptions 来配置。

def get_options(self) -> StepOptions:
return StepOptions(
execute_retry=RetryPolicy(
initial_interval=timedelta(seconds=1),
backoff_coefficient=2,
maximum_attempts=5,
),
)

def execute(self, context, ready_after_attempt: int) -> StepDecision:
if context.attempt < ready_after_attempt:
raise RuntimeError(f"not ready on attempt {context.attempt}")
return graceful_complete("ready")

例子: examples/python/dex_examples/primitives/step/retry_flow.py

WaitFor failure policy

WaitFor method retry 耗尽时:

  • FailFlow — 失败 Flow。这是默认行为。
  • PROCEED — 继续调用 Execute。

使用 PROCEED 时,同一 Step 的 Execute 收到不变的 durable input。waitForMethodFailed() 返回 true。getRecoveryError() 包含最后一次失败 WaitFor attempt 的 error_type 和 detail。

def get_step_options(self) -> StepOptions:
return StepOptions(
wait_for_retry=RetryPolicy(maximum_attempts=2),
wait_for_failure=WaitForFailurePolicy.PROCEED,
)

def wait_for(self, context: Context, input: str) -> Wait:
raise RuntimeError("planned WaitFor failure")

def execute(self, context: Context, input: str) -> StepDecision:
if not context.wait_for_method_failed():
raise RuntimeError("waitFor failure was not reported")
return go_to(FinishStep, f"{input}_recovered")

例子: examples/python/dex_examples/primitives/proceed_on_wait_failure/proceed_on_wait_failure_flow.py

Execute failure policy

Execute method retry 耗尽时,onExecuteFailureProceedTo / ExecuteFailure.proceedTo(...) 前往带有相同 input 的 recovery Step

def get_step_options(self) -> StepOptions:
return StepOptions(
execute_retry=RetryPolicy(maximum_attempts=5)
).on_execute_failure_proceed_to(UpdateQuantityRecovery)

例子: examples/python/dex_examples/patterns/recovery/failure_recovery_flow.py

Failure Handling 模式与 money-transfer 用例。

recovery Step 收到失败 Step 不变的 durable input。getRecoveryError() 包含最后一次失败 Execute attempt 的 error_type 和 detail。

Step Failed 事件与 last failure info

  • 终态事件 StepExecuteFailed / StepWaitForFailed 在 Step 最终失败时携带 failure output。
  • Retry 期间(failure policy 运行前),Step 事件与 live Flow 状态暴露 lastFailureInfo——最近一次 attempt 的错误(type、detail、worker 元数据)。
  • 在 Dex Web 中打开事件详情,可在 retry 进行中查看 Last failure。Flow 概览中的活跃 Step 也显示 lastFailureInfo。

Last failure info 描述 retry attempt。Failure policy 决定 retry 结束后的行为。