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

# 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/reference/rust/step-options.md#stepoptions-override-per-stepexecution).

```rust
Ok(StepDecision::go_to_many([
    StepMovement::to(&CarrierA, quote_a),
    StepMovement::to(&CarrierB, quote_b),
    StepMovement::to(&Winner, winner_quote),
]))
```

Example: [examples/rust/src/primitives/step_decision/flow.rs](https://github.com/superdurable/dex/tree/main/examples/rust/src/primitives/step_decision/flow.rs)

<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.

```rust
"graceful" => Ok(StepDecision::graceful_complete(String::from("done"))),
"dead-end" => Ok(StepDecision::go_to_many([
    StepMovement::to(&BranchWorker, "left".to_string()),
    StepMovement::to(&BranchWorker, "right".to_string()),
])),

Ok(StepDecision::dead_end())
```

Example: [examples/rust/src/primitives/step_decision/flow.rs](https://github.com/superdurable/dex/tree/main/examples/rust/src/primitives/step_decision/flow.rs)

```rust
fn execute(&self, _context: &mut Context, _input: ()) -> HandlerResult<StepDecision> {
    Ok(StepDecision::force_fail("task exceeded graceful timeout"))
}

fn execute(&self, _context: &mut Context, _successful: bool) -> HandlerResult<StepDecision> {
    Ok(StepDecision::force_complete("task-completed".to_string()))
}
```

Example: [examples/rust/src/patterns/timeout/flow.rs](https://github.com/superdurable/dex/tree/main/examples/rust/src/patterns/timeout/flow.rs)

<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/reference/server/runtime-data.md#cancel-running-steps). For how a
running attempt observes cancellation, see [Cancellation](https://docs.superdurable.io/reference/rust/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/reference/server/runtime-data.md#canceled-step-messages).

```rust
Ok(StepDecision::go_to(&RecordQuote, quote)
    .cancel_step(&CarrierA)
    .cancel_step(&CarrierB))
```

Example: [examples/rust/src/primitives/step_decision/flow.rs](https://github.com/superdurable/dex/tree/main/examples/rust/src/primitives/step_decision/flow.rs)

<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/design-patterns/draining-channel-for-external-publishing.md)
for the full example.

```rust
Ok(StepDecision::force_complete_if_channels_empty(
    (),
    StepMovement::to(&DrainChannel, ()),
    [channel_queue().when_empty()],
))
```

Example: [examples/rust/src/patterns/drain_channels/flow.rs](https://github.com/superdurable/dex/tree/main/examples/rust/src/patterns/drain_channels/flow.rs)
