Skip to main content

Step decision

This page covers the advanced StepDecision features. See the basic page for the basic features.

Multiple next Steps

GoTo starts one next Step. GoToMany starts multiple next Steps. Use it to fan out work that can run in parallel. Each Step movement has its own input and can also have its own Step options.

return go_to_many(
StepMovement.of(CarrierAStep, Quote(carrier="A", price=10)),
StepMovement.of(CarrierBStep, Quote(carrier="B", price=12)),
StepMovement.of(WinnerStep, quote),
)

Example: examples/python/dex_examples/primitives/step_decision/step_decision_flow.py

Close decisions

DecisionWhat it does
GracefulCompleteStops this branch and triggers the Flow to prepare for completion. When all branches and Steps are stopped, the Flow completes.
DeadEndStops this branch only.
ForceCompleteCompletes the Flow immediately.
ForceFailFails the Flow immediately.

GracefulComplete and ForceComplete can return an output. ForceFail returns a failure reason. The Flow result returns each output with the Step type and Step execution ID. When multiple Steps complete gracefully, all their outputs return together.

A Flow can have no active Steps and still keep running. DeadEnd stops this branch without making a decision that triggers the Flow to complete.

Use GracefulComplete when you want the remaining active Steps and branches to finish gracefully. Use DeadEnd when you do not want this branch to make a decision that triggers the Flow to complete. Use ForceComplete or ForceFail when you want to make an immediate decision.

if mode == "graceful":
return graceful_complete("done")
if mode == "dead-end":
return go_to_many(
StepMovement.of(BranchWorkerStep, "left"),
StepMovement.of(BranchWorkerStep, "right"),
)

return dead_end()

Example: examples/python/dex_examples/primitives/step_decision/step_decision_flow.py

def execute(self, context: Context, input: None) -> StepDecision:
return force_fail("Workflow did not finish the task in time")

def execute(self, context: Context, input: bool) -> StepDecision:
return force_complete("Workflow completed successfully")

Example: examples/python/dex_examples/patterns/timeout/flow_graceful_timeout.py

Cancellation

Return a StepDecision that can cancel other active Steps.

There are two types of cancellation:

  • CancelSteps selects active Steps by Step type.
  • CancelSiblingSteps selects active Steps that were triggered by the same parent Step execution.
return (
go_to(RecordQuoteStep, quote)
.with_canceling_steps(self.flow.carrier_a, self.flow.carrier_b)
)

Example: examples/python/dex_examples/primitives/step_decision/step_decision_flow.py

ForceCompleteIfChannelsEmpty

ForceCompleteIfChannelsEmpty atomically checks whether all named Channels are empty. A Channel with queued messages is non-empty. After a message is consumed and committed to a Step, that Channel remains non-empty until the Step finishes processing Execute. If every named Channel is empty, it completes the Flow. Otherwise, it goes to other Steps.

Use it when you want to drain Channels and complete the Flow, so the Flow can stay short. See Drain External Channel for the full example.

return force_complete_if_channels_empty(
None,
StepMovement.of(ProcessMessage, None),
self.queue_channel,
)

Example: examples/python/dex_examples/patterns/drain-channels/external_publishing/draining_channel_flow.py