# async / await and Task

> C#'s async and await, with C#'s meaning. A call to a Task-returning method that you do not await where you make it starts a task that runs beside the caller; await joins it. Awaiting the call where you make it is just the call. Inside a durable run every task is journaled, so a run that is resumed does not do finished work again.

<!-- id: function-async-await · area: function · stability: stable · html: https://osysharp.com/reference/function/async-await/ -->

## Summary        {#summary}
**`async`, `await` and `Task<T>` mean what they mean in C#.** Mark a method `async`, give it a `Task<T>` return, and
its body returns the `T`. Call it and `await` the call, and you get the `T` back — that is an ordinary call.

Call it **without** `await` and you get a **`Task<T>`**: the method starts running beside you, and you carry on.
`await` the task later to get its result. That is how two outbound calls overlap instead of waiting for each other:

```osy syntax
var rates  = FetchRates(day);       // starts — and carries on
var stock  = FetchStock(sku);       // starts too; both are in flight now
var total  = await rates + await stock;   // wait for both
```

Everything `await` waits for is real: the two calls above are in flight **at the same time**, on the server.

## Signature      {#signature}
```osy syntax
async Task<T> Name(params) { … return value; }   // the body returns the T
async Task Name(params) { … }                      // returns nothing
async ValueTask<T> Name(params) { … }              // the same as Task<T> here

var t = Name(args);        // START it — a Task<T>, running beside you
T v   = await t;           // join it: its result, or its failure rethrown
T w   = await Name(args);  // await where you call it: the plain call, nothing started
```

`async` stands with a function's other modifiers in any order, as in C#: `public async Task<T> Name()`,
`async public …`, `internal async …`, `public static async …`. On a top-level function `static` is accepted and adds
nothing — a top-level function belongs to no object already.

| you write | what happens |
|---|---|
| `await Fetch(x)` | the call, exactly as without `async` — nothing runs beside you |
| `var t = Fetch(x);` | `Fetch` starts and runs beside the caller; `t` is its `Task<T>` |
| `await t` | wait for `t`; answer its result, or rethrow what it threw |
| `t.Result` · `t.Wait()` · `t.GetAwaiter().GetResult()` | the same join, written C#'s blocking way — nothing here holds a thread, so it cannot deadlock. As in C#, `.Result` and `.Wait()` raise an `AggregateException` over a failure, where `await` and `GetResult()` raise the failure itself |
| `Task.Run(() => …)` · `Task.Factory.StartNew(() => …)` · `Task.Run(() => …, token)` | the lambda runs as a task beside you — a block body (`() => { …; return x; }`) too, in a component as well as on the server |
| `t.ContinueWith(prev => …)` | a task that waits for `t` (succeeded or not) and then runs the lambda with it |
| `_ = Fetch(x);` | started on purpose with nobody waiting; if it fails, the failure is logged |
| `Fetch(x);` on its own | refused — nothing would ever wait for it (C#'s CS4014, an error here); write `await` or `_ =` |
| `t.IsCompleted` · `IsFaulted` · `IsCanceled` · `Status` · `Exception` | the task's state, read now — journaled in a durable run |
| `await foreach (var x in Items())` | read an `IAsyncEnumerable<T>` / `stream<T>` |

## Description    {#description}

### What does a task run, and where?   {#legs}
A task started on the server is a **leg**: the method runs on its own beside the caller, with the arguments the caller
evaluated. The caller does not wait until it says `await`. A run does not finish while a task it started is still
running — it waits for every one — so nothing you start is ever left running after its request has ended.

Use it for work that waits on **someone else**: outbound HTTP calls, a model completion, a slow read. Two of those
started together take as long as the slower one, not as long as both.

### Can a task write data?   {#writes}
**Not to its caller's unit of work.** A task runs at the same time as its caller, and the two would race over the same
pending changes. So the compiler refuses a started task whose method creates, changes or deletes a row — directly or
through a function it calls — and says what to do:

```console
`Save` runs as a task here — it is not awaited where it is called — and it creates a Note. A task runs beside its
caller, so it may not write to the caller's unit of work: the two would race. Await it where it is called
(`await Save(…)`) so its writes join the caller's, or return what should be written and write it after the `await`.
```

A write the compiler cannot see — one behind an interface, or in a package — is refused when the task finishes, with
the same sentence, and nothing it staged is kept. `UnitOfWork.Commit()` inside a task is refused at once: it would
commit the caller's half-finished work.

Reading is fine. A task reads what its caller can read, through the caller's own permissions.

A task may still write in two ways, each in a unit of work that is **not** the caller's: call a function marked
[[function-commits-alone|`[CommitsAlone]`]], and run a block as a declared actor — `runas (Robot) { … }` — whose
writes are the actor's and are committed as the block ends ([[security-declared-actor#beside]]). The compiler does
not count either as a write of the task's.

### What happens if the process dies?   {#durable}
Inside a durable run (a workflow body, and every function it calls) each task is **journaled**. When a task finishes,
its result is recorded on its own transaction, straight away. If the run is killed and resumed, a task that had
finished is not run again — its recorded result is the task. A task that had not finished runs again, exactly as a
`Workflow.Once` step would.

Before a run suspends — a hand-off to the browser, a park on a workflow — it waits for every running task, so what is
carried across the suspension is only ever a finished task.

### And in the browser?   {#browser}
A page's methods can be `async` too, and `async void` is accepted on a component method — it is C#'s event-handler
case, and a component method bound to a click is exactly that. In the browser a task's call runs where the task is
started and the task is finished from then on: the case C# calls a task that completes synchronously. Every value an
`await` answers, where a failure surfaces, and what `Task.WhenAll` and `Task.WhenAny` answer are the same as on the
server. What the browser does not do is overlap the calls; an outbound call is the server's anyway.

### What does a task's state answer?   {#state}
`t.IsCompleted`, `t.IsCompletedSuccessfully`, `t.IsFaulted`, `t.IsCanceled`, `t.Status` (a `TaskStatus`, C#'s members
and numbers) and `t.Exception` (an `AggregateException` whose message names the failure, or `null`) answer what the
task is doing at the moment you ask. That is a race — the task may finish a moment later — so inside a durable run the
**first** reading of each is written to the run's journal, and a run that is resumed reads the same answer back.

### And `await foreach`?   {#streams}
`async IAsyncEnumerable<T> Items() { … yield return x; … }` is an async stream — the same thing as a `stream<T>`
producer — and `await foreach (var x in Items())` reads it. A plain `foreach` is the same loop
([[function-foreach#stream]]). The loop body runs on each item as it arrives, as in C#, and leaving the loop stops
the reading. Only if the body has to wait on something outside the run — the browser, a person, a durable delay — is
the rest of the stream read to its end at that moment, because a run that is put away cannot hold a half-read stream.

### What is refused, and what to write instead?   {#refused}
| you write | why | write instead |
|---|---|---|
| `async void F()` outside a component | nothing can await it or see it fail | `async Task F()` |
| `async string F()` | an `async` method returns a task (C#'s CS1983) | `async Task<string> F()` |
| `t.Wait(timeout)` | a join with a time limit | `await Task.WhenAny(t, Task.Delay(timeout))` |
| `Thread`, `SynchronizationContext`, `TaskScheduler`, `AsyncLocal<T>` | a body never owns a thread, and nothing flows invisibly across a pause | `Task.Run`, `Task.Delay`, a `SemaphoreSlim`, a parameter |
| `await 5` | a value is not a task | drop `await` |

`t.ConfigureAwait(false)` is accepted and changes nothing — there is no synchronization context to return to.
`t.AsTask()` answers `t`. `using System.Threading.Tasks;` is accepted and imports nothing: `Task` is always in scope.

An app that declares its own `entity Task` keeps it: `Task` alone means the entity, while `Task<T>`, `async Task` and
`Task.WhenAll(…)` mean the built-in.

## Examples       {#examples}
```osy title="two outbound calls in flight at once, then joined" test app=function-async-await
app Rates {
  model "model/**/*.osy";
  use Osysharp.Http;
}

async Task<decimal> Rate(string currency) {
  var r = Http.Get("https://rates.example/" + currency);
  return decimal.Parse(r.Body);
}

async Task<decimal> Basket(decimal eur, decimal usd) {
  var euro = Rate("EUR");
  var dollar = Rate("USD");
  return eur * await euro + usd * await dollar;
}
```

```osy title="a task that is not async: hand back a task you already have" test app=function-async-await
Task<decimal> Cached(decimal known) {
  return Task.FromResult(known);
}

async Task<decimal> Either(bool haveIt, decimal known) {
  return haveIt ? await Cached(known) : await Rate("EUR");
}
```

```osy title="the write happens after the await, in the caller's unit of work" test app=function-async-await
entity Quote { [MaxLength(10)] string Currency; decimal Value; }

async Task<decimal> Remember(string currency) {
  var rate = Rate(currency);          // reads and an outbound call: fine as a task
  var value = await rate;
  new Quote { Currency = currency, Value = value };   // the write, after the await
  return value;
}
```

```osy title="a lambda as a task, and a continuation" test app=function-async-await
async Task<int> Scores() {
  var total = Task.Run(() => {
    var sum = 0;
    for (var i = 1; i <= 4; i++) { sum += i * i; }
    return sum;
  });
  var doubled = total.ContinueWith(done => done.Result * 2);
  return await doubled;
}
```

```osy title="start one on purpose and do not wait for it" test app=function-async-await
async Task Ping(string where) { Http.Get("https://status.example/" + where); }

async Task<string> Report() {
  _ = Ping("report");       // fire and forget — a failure is logged, not thrown here
  return "sent";
}
```

## See also       {#see-also}
- [Wait for several tasks (Task.WhenAll, Task.WhenAny)](https://osysharp.com/reference/function/task-whenall/) — waiting for several tasks, or for the first
- [Stop a task (CancellationToken) and complete one by hand (TaskCompletionSource)](https://osysharp.com/reference/function/cancellation/) — stopping a task with a CancellationToken; TaskCompletionSource
- [Do the same work for many items at once (Parallel, SemaphoreSlim)](https://osysharp.com/reference/function/parallel/) — `Parallel.For` / `ForEach` / `ForEachAsync`, and `SemaphoreSlim`
- [Wait in place (Task.Delay)](https://osysharp.com/reference/function/task-delay/) — `await Task.Delay(…)`, and a delay as a task
- [Parallel legs (start several, then wait for them)](https://osysharp.com/reference/workflow/parallel-legs/) — parallel child workflows inside a saga, each with its own compensation
- [Http.*](https://osysharp.com/reference/http/facade/) — `Http.Get` / `Http.Post`, the calls worth overlapping
- [UnitOfWork](https://osysharp.com/reference/function/unit-of-work/) — the unit of work a task may not write to
