---
title: "Step decisions"
description: "Execute returns a StepDecision. The decision moves to next Steps,"
canonical_url: "https://docs.superdurable.io/zh-Hans/reference/go/step-decisions/"
source: "docs/reference/go/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/go/step-options.md#stepoptions-override-per-stepexecution).

```go
return dex.GoToMany(
	dex.MovementOf(carrierAStep{}, Quote{Carrier: "A", Price: 10}),
	dex.MovementOf(carrierBStep{}, Quote{Carrier: "B", Price: 12}),
	dex.MovementOf(winnerStep{}, quote),
), nil
```

Example: [examples/go/primitives/step-decision/workflow.go](https://github.com/superdurable/dex/tree/main/examples/go/primitives/step-decision/workflow.go)

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

```go
case "graceful":
	return dex.GracefulComplete("done"), nil
case "dead-end":
	return dex.GoToMany(
		dex.MovementOf(branchWorker{}, "left"),
		dex.MovementOf(branchWorker{}, "right"),
	), nil

func (branchWorker) Execute(_ dex.Context, _ string) (*dex.StepDecision, error) {
	return dex.DeadEnd(), nil
}
```

Example: [examples/go/primitives/step-decision/workflow.go](https://github.com/superdurable/dex/tree/main/examples/go/primitives/step-decision/workflow.go)

```go
func (timeoutStep) Execute(
	ctx dex.Context,
	_ dex.None,
) (*dex.StepDecision, error) {
	return dex.ForceFail("Workflow did not finish the task in time"), nil
}

func (taskStep) Execute(
	ctx dex.Context,
	_ bool,
) (*dex.StepDecision, error) {
	return dex.ForceComplete("Workflow completed successfully"), nil
}
```

Example: [examples/go/patterns/timeout/workflow.go](https://github.com/superdurable/dex/tree/main/examples/go/patterns/timeout/workflow.go)

<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/go/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).

```go
func (winnerStep) Execute(_ dex.Context, quote Quote) (*dex.StepDecision, error) {
	return dex.GoTo(recordQuote{}, quote).
		CancelSteps(carrierAStep{}, carrierBStep{}), nil
}
```

Example: [examples/go/primitives/step-decision/workflow.go](https://github.com/superdurable/dex/tree/main/examples/go/primitives/step-decision/workflow.go)

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

```go
return dex.ForceCompleteIfChannelsEmpty(
	nil,
	[]dex.ChannelDef{QueueChannel},
	dex.MovementOf(processMessage{}, ""),
), nil
```

Example: [examples/go/patterns/drain-channels/external-publishing/workflow.go](https://github.com/superdurable/dex/tree/main/examples/go/patterns/drain-channels/external-publishing/workflow.go)
