---
title: "Step decisions"
description: "Execute returns a StepDecision. The decision moves to next Steps,"
canonical_url: "https://docs.superdurable.io/zh-Hans/reference/python/step-decisions/"
source: "docs/reference/python/step-decisions.mdx"
locale: "zh-Hans"
---

# Step decisions

**Execute** returns a **StepDecision**. The decision moves to next Steps,
closes the Flow, or stops this branch. It can also cancel other Steps.

<a id="gotomulti"></a>

## Multiple next Steps

**GoTo** starts one next Step. **GoToMany** starts multiple next Steps. Each
Step movement has its own input and can also have its own
[Step options](https://docs.superdurable.io/zh-Hans/reference/python/step-options.md#stepoptions-override-per-stepexecution).

```python
return go_to_many(
    StepMovement.of(CarrierA, Quote(carrier="A", price=10)),
    StepMovement.of(CarrierB, Quote(carrier="B", price=12)),
    StepMovement.of(Winner, quote),
)
```

Example: [examples/python/dex_examples/primitives/step_decision/step_decision_flow.py](https://github.com/superdurable/dex/tree/main/examples/python/dex_examples/primitives/step_decision/step_decision_flow.py)

<a id="close-decisions"></a>

## Close decisions

| Decision             | What it does                                                                                                 |
| -------------------- | ------------------------------------------------------------------------------------------------------------ |
| **GracefulComplete** | Stops this branch and marks the Flow to complete. The Flow completes when every branch and Step has stopped. |
| **DeadEnd**          | Stops this branch only.                                                                                      |
| **ForceComplete**    | Completes the Flow immediately.                                                                              |
| **ForceFail**        | Fails the Flow immediately.                                                                                  |

**GracefulComplete** and **ForceComplete** can carry an output. **ForceFail**
carries a failure reason. The Flow result lists each output with its Step type
and Step execution ID. When several Steps complete gracefully, the result
contains all their outputs.

**DeadEnd** stops this branch without marking the Flow to complete. A Flow with
no active Steps can keep running.

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

return dead_end()
```

Example: [examples/python/dex_examples/primitives/step_decision/step_decision_flow.py](https://github.com/superdurable/dex/tree/main/examples/python/dex_examples/primitives/step_decision/step_decision_flow.py)

```python
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](https://github.com/superdurable/dex/tree/main/examples/python/dex_examples/patterns/timeout/flow_graceful_timeout.py)

<a id="cancellation-on-stepdecision"></a>

## Cancel other Steps

A **StepDecision** can cancel other active Steps.

- **CancelSteps** selects active Steps by Step type.
- **CancelSiblingSteps** selects active Steps that were triggered by the same
  parent Step execution.

An RPC can also cancel Steps by type. See
[Cancel running Steps](https://docs.superdurable.io/zh-Hans/reference/server/runtime-data.md#cancel-running-steps). For how a
running attempt observes cancellation, see [Cancellation](https://docs.superdurable.io/zh-Hans/reference/python/step-options.md#cancellation).

When Dex cancels a Step before its **Execute** commits, it returns the Channel
messages that the Step's wait consumed. They go back to the front of their
Channels, in their original order. A Step that the decision cancels also never
receives the messages that the same decision publishes. Neither applies when
the decision also closes the Flow with **ForceComplete** or **ForceFail**. See
[Canceled Steps return consumed messages](https://docs.superdurable.io/zh-Hans/reference/server/runtime-data.md#canceled-step-messages).

```python
return (
    go_to(RecordQuote, quote)
    .with_canceling_steps(self.flow.carrier_a, self.flow.carrier_b)
)
```

Example: [examples/python/dex_examples/primitives/step_decision/step_decision_flow.py](https://github.com/superdurable/dex/tree/main/examples/python/dex_examples/primitives/step_decision/step_decision_flow.py)

<a id="forcecompleteifchannelsempty"></a>

## ForceCompleteIfChannelsEmpty

**ForceCompleteIfChannelsEmpty** checks all named Channels in one atomic step.
If every one is empty, it completes the Flow. Otherwise, it goes to the given
next Steps. A Channel with queued messages is non-empty. A Channel also stays
non-empty after a Step consumes a message from it, until that Step's
**Execute** finishes. A message that a canceled Step returned is pending again,
so its Channel is non-empty too.

Use it to complete a Flow once its Channels are drained, so the Flow stays
short. See
[Drain External Channel](https://docs.superdurable.io/zh-Hans/design-patterns/draining-channel-for-external-publishing.md)
for the full example.

```python
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](https://github.com/superdurable/dex/tree/main/examples/python/dex_examples/patterns/drain-channels/external_publishing/draining_channel_flow.py)
