OxL Reference

8.4 Chains

A chain links asynchronous steps so that either the whole chain is executed or the first unhandled error is returned.

oxl
let page = Users.get(id)
  -> (Orders.recent(it.id), Recs.for(it.id))
  -> (orders, recs) => Page{ orders, recs }
  ~> Audit.log("page", id)
  !> Timeout => Page.empty()
  within PAGE_DEADLINE
  retry 2

let html = await page

Syntax: head ( link )* ( suffix )*, where a link is -> step, ?-> step, ~> step, !> pattern => handler; a suffix is within e, retry e (on Types)? (backoff e)?.

The head is an expression of type Task<T, E>, a call of a suspendable function (lifted to a Task by §6.3) or any other expression (a ready value).

A step is one of:

  1. an expression that uses it — the value of the previous step;
  2. a lambda x => e or one with destructuring (a, b) => e;
  3. a tuple (e1, …, en) — fan-out: each ei is evaluated as a separate task in parallel (it is available inside ei); the result is a tuple of values; the first error cancels the others.

The result of a step that is a call of a suspendable function or a Task is awaited. If the result type contains errors and the step returned an error, the remaining links to the right are skipped up to the nearest matching !>.

LinkSemantics
-> stepexecute the step over the value on the left
?-> stepif the value on the left is none, the result of the chain is none (none is added to the type), otherwise execute the step
~> stepstart the step in the background; the value of the chain stays the same; step errors are written to the log and not propagated; the background task lives in the node's background scope (§8.5)
!> P => hcatches an error matching pattern P from the whole part of the chain to the left; the value of h replaces the value of the left part and execution continues with the links to the right; h may fail
within da deadline for the whole part to the left; exceeding it is the error Timeout (which a !> to the right can catch)
retry nrepeat the whole part to the left up to n times on the errors Timeout | Unavailable (or those listed in on); the default backoff is exp(100ms, 10s) with jitter

Chain type — Task<T, E>, where T is the type of the last value (with none if there is a ?->), E is the union of the errors of all steps minus those caught by !> plus the errors of handlers, plus Timeout with within.

Starting: a chain is lazy. It is started by await, spawn, passing to a lazy parameter or use in statement position (then it is awaited implicitly, like a call of a suspendable function).

it refers to the nearest enclosing chain; in a nested chain the outer value has to be named with a lambda.

it-outside-chain

See also

Source: docs/spec/oxl-standard.en.md