Skip to Content

Cancellation and Timeout

Cancellation produces no error; it follows negotiation semantics: the function declares itself cancellable, and when cancelled it returns a value through an ordinary return in its body — the task completes normally.

The cancellable Function

import Async.*; cancellable async func Work() -> int { await 5s; if cancel.requested { return -1; } return 42; }

Once marked cancellable, the function body gains cancel.requested and cancel.token.

cancel and timeout

async func main() -> int { val cts = new CancellationTokenSource(); val t = Work() cancel cts.Token; cts.Cancel(); print(await t); print(await Work() timeout 100ms); return 0; }
-1 -1

timeout on a task Value

A spawn result stored in a variable can still be given a deadline; the syntax is the timeout suffix:

val t = spawn { await 5s; return 99; }; val t2 = t timeout 500ms; print(await t2);
0

At the timeout deadline, the underlying task is finalized as cancelled: no parallel new task is produced — it is the decorated task itself that reaches a terminal state, and await t2 continues with the type’s default value.

Combinators

async func Quick() -> int { await 20ms; return 9; } val both = await all([Quick(), Quick()]); print(both); val first = await any([Quick(), Quick()]); print(first);
[9, 9] 9
  • all: completes only when every task completes, returning a list<T>. The first failure short-circuits into a fault; the process exits with the error and the remaining tasks stop executing;
  • any: the first terminal state decides the result, returning a T. The other tasks are not cancelled and keep running: if the clock keeps advancing after any returns, the losing tasks run to completion as usual — to stop them you must cancel them yourself;
  • allSettled: waits for every terminal state; the returned list is ordered by input order (not completion order), with no short-circuit.

The operands take a list<task<T>> or task<T>[]. You can also write it directly: await all([A() cancel ct, B() cancel ct]); after cancellation, each returns its negotiated value.

The Token Family

The token types live in the std::Async module: CancellationTokenSource has Cancel(), CancelAfter(d), and the Token property; the CancellationToken struct has IsCancellationRequested, CanBeCanceled, and the static None().

Notes

  • spawn has a cancellable form too: the body of spawn cancel ct { } is an anonymous cancellable environment, with cancel.* available inside;
  • cancel.* is not visible inside nested lambdas / ordinary nested function bodies, and such a body may not shadow the name cancel.
Last updated on October 11, 2026