zena:task
import {…} from 'zena:task';
Composable combinators for deferred asynchronous operations.
An operation Op<T> is a function returning a Future<T>. This library
provides combinators for wrapping operations with execution policies such as
timeouts (timeout), retries with backoff (retry), deadlines (deadline),
and fallbacks (fallback).
Examples ​
import { retry, timeout, Op } from 'zena:task';
import { milliseconds } from 'zena:time';
let fetchWithRetry = retry(3, timeout(milliseconds(500), myFetchOp));
let future = fetchWithRetry();
Classes
TimeoutError
class TimeoutError extends Error
How timeout and deadline report an attempt that ran out of
budget. Carries the budget so a retry layer's log can say which.
TaskState
sealed class TaskState<T>
Where a task's latest run stands. Cancellation is not a state: a cancelled run restores the state the task held before it (docs/design/task.md, "The state, as data").
Initial
final class Initial<T> extends TaskState<T>
No run has settled yet.
Pending
final class Pending<T> extends TaskState<T>
A run is in flight. Deliberately carries no future: only the latest run's outcome ever becomes the state, and a held future could outlive its run's relevance.
Complete
final class Complete<T>(value: T) extends TaskState<T>
The latest settled run produced this value.
value: T
Errored
final class Errored<T>(error: Error) extends TaskState<T>
The latest settled run failed with this error.
error: Error
Task
class Task<T>
Runs an operation and exposes where the run stands — Initial,
Pending, Complete, or Errored — across however many runs,
latest-wins (docs/design/task.md).
The op is fixed at construction with its policies already composed:
new Task(retry(3, timeout(milliseconds(100), fetchUser))). Each
run starts the op inside a child CancelScope, so a superseding
run() cancels the previous attempt's whole subtree rather than
racing it for the state.
new(op: Op<T>, onChange: (() => void)? = null)
changed(): Future<void>
Settles at the next state transition after the call.
run(): Future<T>
Starts a run, cancelling a pending previous one — superseded before it arrived, its outcome discarded. Returns this run's future, which settles the way the run does even if superseded.
cancel(): void
Cancels a pending run; the previous settled state is restored when the cancellation lands. A task with no run pending is unchanged.
Type aliases
Op
type Op<T> = () => Future<T>
An operation that can be attempted. Each call starts one fresh attempt and hands back its future.
Functions
timeout
function timeout<T>(budget: Duration, op: Op<T>): Op<T>
Bounds each attempt to budget of wall time: the attempt races its
budget, and whichever loses is cancelled. An attempt that exceeds
the budget fails with TimeoutError — a failure like any other, so
an outer retry treats a timeout as retryable.
deadline
function deadline<T>(at: Instant, op: Op<T>): Op<T>
Bounds each attempt to finish before an absolute point on the
monotonic clock (monotonic()), however many layers retry it:
where timeout gives every attempt a fresh budget, a deadline
spends one budget across all of them. An attempt starting past the
deadline fails immediately, without running the operation.
retry
function retry<T>(attempts: i32, op: Op<T>, firstDelay: Duration = milliseconds(0)): Op<T>
Runs up to attempts attempts, handing back the first value; the
last attempt's failure propagates. With firstDelay, waits that
long before the second attempt and doubles the wait each time after.
Retrying is the reason Op is a function: each attempt is a fresh
call. Cancellation is not retried — see the module comment.
fallback
function fallback<T>(op: Op<T>, alt: Op<T>): Op<T>
Tries op; on failure, answers with alt instead. The failure
that triggered the fallback is discarded — when it matters, catch
it yourself. Cancellation is not a failure: if op's attempt
completes cancelled, the unwind passes through and alt never
runs.
hedge
function hedge<T>(delay: Duration, op: Op<T>): Op<T>
Starts a second attempt if the first has not settled within
delay, and hands back whichever settles first, value or
failure — the tool for an operation that is usually fast and
occasionally very slow. The loser is cancelled. A hedge trims
slowness and does not mask errors; layer retry on top for that.