# Workflow.Run (start a workflow)

> Start the workflow bound to an entity's type, on that entity. Bare — `Workflow.Run(order)` — is fire-and-forget: start it and carry on. Awaited — `await Workflow.Run("fulfil", order)` — is a durable wait on the started (child) workflow: hold until it reaches a terminal, then return on success or throw `WorkflowError` / `WorkflowCancelled` on an error / cancel terminal, so a parent flow can compensate with an ordinary `try`/`catch`.

<!-- id: workflow-run · area: workflow · stability: stable · html: https://osysharp.com/reference/workflow/run/ -->

## Summary        {#summary}
**`Workflow.Run(order)`** starts the workflow whose target binds the entity's **type**, on that entity — the same
inference [Raising a workflow event](https://osysharp.com/reference/workflow/raise/) uses for its events. There are two forms, and the only difference is `await`:

- **`Workflow.Run(order)`** (bare) — **fire-and-forget**: start it and carry straight on. The call returns nothing.
- **`await Workflow.Run("fulfil", order)`** — a **durable wait**: hold here until the started workflow reaches a **terminal**,
  then hand its outcome back. A **success** terminal lets the next line run; an **error** terminal throws
  **`WorkflowError`**; a **cancel** terminal throws **`WorkflowCancelled`**. That makes a child workflow a step you can
  wrap in an ordinary `try`/`catch` and compensate — the Saga pattern.

`await` carries meaning **only** on `Workflow.Run` — it is the one place in Osy# where you wait. Everywhere else effects
run in place, so `await` is never written.

## Signature      {#signature}
```osy syntax
Workflow.Run(order)          // fire-and-forget — start it, carry on; returns nothing
await Workflow.Run("fulfil", order)    // wait for the started workflow's terminal, then return / throw on its outcome
```

`entity` is an entity-typed value whose type has exactly one workflow bound to it in the same unit. More than one is a
compile error (the target is ambiguous); none is a compile error (nothing to start).

## Description    {#description}
A workflow is bound to an entity type (`Tracks = <Entity>.<Enum>;`). `Workflow.Run(order)` starts that workflow on the
given `order` row. Use the **bare** form when the started workflow runs independently — you don't need its result:

```osy title="the bare form — nothing to wait for" syntax
var welcome = new WelcomeEmail { Customer = this.Item };
Workflow.Run(welcome);        // kick it off; this flow carries on
```

Use the **awaited** form when the started workflow is a **step** whose outcome you act on — the essence of a Saga. The
started (child) workflow's terminal surfaces at the `await`:

- a **`success`** terminal → the `await` returns and the next line runs;
- an **`error`** terminal → the `await` throws **`WorkflowError`**;
- a **`cancel`** terminal → the `await` throws **`WorkflowCancelled`**.

Both faults carry the terminal state's message, and both are ordinary catchable exceptions — so a compensating flow is
just `try`/`catch`:

```osy title="the awaited form: catch the fault and compensate" syntax
try {
  await Workflow.Run("payment", payment);        // hold until the payment workflow reaches a terminal
  goto Confirmed;                      // reached only if it SUCCEEDED
} catch (WorkflowError e) {
  await Workflow.Run("refundHold", new RefundHold { Order = this.Item });   // compensate — undo the earlier step
  goto Refunded;
}
```

`WorkflowError` (an error terminal) and `WorkflowCancelled` (a deliberate cancel) are distinct on purpose: catch them
separately when a cancel is not a failure. A `catch (Exception e)` still catches either.

## Examples       {#examples}
```osy title="starting a second workflow from a state" test app=workflow-run
enum OrderState { Placed, Done }

[Principal]
entity Person {
  [Required, MaxLength(200)] string Email;
  security { allow read, create when IsAuthenticated; }
}

entity Order {
  [Required, MaxLength(60)] string Reference;
  OrderState Status;                       // no default: the workflow owns this field
  security { allow read, create, update when IsAuthenticated; }
}

enum NoticeState { Sending, Sent }

entity ShipmentNotice {
  [Required] Order Order;
  NoticeState Status;
  security { allow read, create, update when IsAuthenticated; }
}

workflow NoticeFlow {
  Tracks    = ShipmentNotice.Status;
  Autostart = true;
  Initial   = Sending;
  state Sending { on Complete { goto Sent; } }
  terminal success Sent { }
}

workflow OrderFlow {
  Tracks    = Order.Status;
  Autostart = true;
  Initial   = Placed;

  event Ship();

  state Placed {
    subscribe Ship();
    on Ship {
      // Fire-and-forget: the notice runs on its own, with its own durability.
      // The argument is an entity-typed VARIABLE — `Workflow.Run(new …)` is refused.
      var notice = new ShipmentNotice { Order = this.Item };
      Workflow.Run(notice);
      goto Done;
    }
  }
  terminal success Done { }
}
```

Fire-and-forget — start a notification workflow and move on:
```osy title="fire-and-forget: start a notice and carry on" syntax
var notice = new ShipmentNotice { Order = this.Item };
Workflow.Run(notice);
```

Awaited step with compensation — the Saga shape:
```osy title="the saga shape — a route per terminal outcome" syntax
try {
  await Workflow.Run("reservation", reservation);     // a child workflow; wait for its terminal
} catch (WorkflowError e) {
  goto Rejected;                       // it failed — route accordingly
} catch (WorkflowCancelled e) {
  goto Cancelled;                      // it was cancelled — a different route
}
goto Reserved;                         // it succeeded
```

## Notes          {#notes}
- **`await` is the wait, and the only wait.** `Workflow.Run` without `await` never blocks; with `await` it holds until
  the started workflow terminates. Writing `await` on anything else is a compile error.
- The started workflow is inferred from the entity's **type**, exactly like [Raising a workflow event](https://osysharp.com/reference/workflow/raise/). Keep one workflow per
  bound type, or the target is ambiguous.
- **The wait is durable.** When the started workflow waits — on a human step, a timer, or its own child — the awaiting
  flow **parks**: it is persisted and lifted off the thread, then **resumes** exactly where it paused when the child
  reaches a terminal, even across a restart. You write straight-line `await`; the platform owns the pause. Because it
  parks, the compensating `await` inside a `catch` (or a `finally`) works too — the whole `try`/`catch` survives the
  wait.

## See also       {#see-also}
- [Workflows that outlive the code that started them](https://osysharp.com/reference/workflow/change-over-time/) — what happens to a run parked on an awaited child when you deploy past it
- [Raising a workflow event](https://osysharp.com/reference/workflow/raise/) — send a typed event to a running workflow.
- <span class="planned" title="this page is planned and not written yet">workflow-goto</span> — transition within a workflow body.
- [For(entity).Audit](https://osysharp.com/reference/workflow/audit/) — read a workflow's timeline of events.
- [Step labels (naming a child run so it survives a new version)](https://osysharp.com/reference/workflow/park-label/) — naming an awaited child run so a parked run survives a new version.
