As of this writing, the default executor is the only one. It runs all steps in parallel unless values must be provided from one step to another, or in steps that are enclosed by a transaction.
Flows are comprised of steps, which each have an `input` and an `result`. By default, each step is executed concurrently (or at least *may* be executed concurrently). When the result of one step is used in another, that will cause them to run in sequence. In the following flow, for example, the `:create_user` and `:create_blank_project` steps would happen concurrently, but both would wait on the `:create_org` step.
A flow always returns an `%Ash.Flow.Result{}`, and the return value of a successful flow will be available in `%Ash.Flow.Result{result: result}` when the flow did not encounter an error.
If the flow resulted in an error, `error?` is set to `true`, and the result will be `nil`.
## Halting and Resuming Flows
A flow can be halted by using the `halt_if` option on a step, or by a custom step returning `{:error, Ash.Flow.Error.Halted.exception(reason: reason)}`
In this case, the flow will be marked as `complete?: false`. The result of each step up until this point is saved, and you can then rerun the flow with different inputs by passing the incomplete result into the `resume` option when running the flow again. Individual steps can be rerun by deleting them from the `data` field of the flow.
Currently, any error anywhere in the flow will fail the flow and will return an error. Over time, error handling behavior will be added, as well as the ability to customize how transactions are rolled back, and to handle errors in a custom way.
Custom steps allow you to implement any custom logic that you need. There aren't really any restrictions on what you do in a custom step, but there is one main consideration if you want your custom step to play nicely with transactions:
Generally speaking you should set the `touches_resources` if you set `async?` to true.
This ensures that the custom step will be run synchronously if any of those resource's data
layers is in a corresponding transaction. You don't necessarily need to set *all* of the
resources that will be touched. For example, all AshPostgres resources that share the same