Skip to content
velt/task exports

velt/task

API reference

Cancellation with TypeScript's AbortController / AbortSignal (global, as in Node; this module exports them too), timeouts, task scopes (structured concurrency) and task placement. fetch takes a signal. For a walkthrough, read the guide.

import { AbortError, TimeoutError, timeout, taskScope } from "velt/task";

Exports

functionasync

taskScope

#std/task/scope.vlt:178

Re-exported from velt/task/scope

async function taskScope<T, E>(
  body: (scope: TaskScope<E>) => Promise<T> throws E,
  options: ScopeOptions = {},
): Promise<T> throws E

Structured concurrency: runs body with a TaskScope and settles only once the body and every task it spawned with scope.spawn have finished, so no child outlives the scope. The scope fails with the first error in time, of the body or of any child (even one nobody awaited, or whose error the body caught), and otherwise returns the body's result. With cancelOnError (the default), that first error aborts scope.signal, so the other children can stop; their AbortErrors come later and don't replace it.

functionasync

timeout

#std/task/timeout.vlt:27

Re-exported from velt/task/timeout

async function timeout<T, E>(
  p: Promise<T, E>,
  ms: i64,
): Promise<T> throws E | TimeoutError

p, unless it does not settle within ms milliseconds: then TimeoutError. p is raced directly, so after a timeout it is abandoned like a Promise.race loser: a runtime wait (signal.whenAborted(), a timer) is dropped, and a started task keeps running, its rejection handled (pass it a signal to stop it). When p wins, the timer is cancelled at once, so nothing is left waiting.

function

currentWorker

#std/task/workers.vlt:19

Re-exported from velt/task/workers

function currentWorker(): i64

The worker running this task, from 0 to workerCount() - 1; 0 outside a task (a synchronous main). A task stays on its worker with the per-core scheduler (which a program that pins a task gets); otherwise it may move at any await.

function

workerCount

#std/task/workers.vlt:10

Re-exported from velt/task/workers

function workerCount(): i64

How many workers run tasks: fixed for the process (VELT_THREADS, else the number of cores; 1 on WebAssembly), with either scheduler. Calling it doesn't change the scheduler: only pinning a task (spawn(p, { worker })) selects the per-core one.

class

AbortController

#std/task/controller.vlt:9

Re-exported from velt/task/controller

The sending half: abort() aborts its signal.

constructor()No doc comment yet
get signal(): AbortSignal

The controller's signal (the same object every time, like JS).

abort(reason: string = DEFAULT_REASON)

Aborts the signal (a no-op if it already is).

[ [INSPECT]()

How console.log shows the controller, like Node: its signal.

class

AbortError

#std/task/errors.vlt:6

Re-exported from velt/task/errors

class AbortError extends Error

Thrown by throwIfAborted(): the signal's reason is the message.

constructor(reason: string)No doc comment yet

Re-exported from velt/task/scope

class TaskScope<E>

A running taskScope: spawns its child tasks and carries the signal that cancels them. E is the error type of the scope, its body and its children.

constructor(group: shared<Mutex<GroupObj>>, sig: AbortSignal, errors: FirstError<E>, cancelOnError: bool)

Made by taskScope (GroupObj is internal).

get signal(): AbortSignal

The scope's signal: aborted when the body or a child fails (with cancelOnError), on cancel(), and when the scope's task is cancelled. Pass it to the children so they stop cooperatively.

spawn<T>(p: Promise<T, E>): Promise<T, E>

Adds p as a child task of the scope (spawn(p); a call starts on this task, as any promise value); the scope waits for it. A promise that cannot fail (Promise<T>) is accepted too.

cancel(reason: string = DEFAULT_REASON)

Aborts the scope's signal.

class

AbortSignal

#std/task/signal.vlt:46

Re-exported from velt/task/signal

The receiving half: tells work that it should stop.

constructor(cell: SignalCell)

Made by AbortController, taskScope and the static constructors (SignalCell is internal).

get aborted(): bool

Whether abort() was called (or the timeout elapsed).

get reason(): string

The reason passed to abort() ("" while not aborted).

throwIfAborted() throws AbortError

Throws if the signal is aborted: TimeoutError if an AbortSignal.timeout aborted it, otherwise AbortError with the reason as its message.

whenAborted(): Promise<void>

Resolves once the signal is aborted (never, if it never is). Race it directly against work: Promise.race([work(), signal.whenAborted()]).

static timeout(ms: i64): AbortSignal

A signal that aborts by itself after ms milliseconds (reason "timed out after <ms> ms"; throwIfAborted() throws TimeoutError).

static any(signals: AbortSignal[]): AbortSignal

A signal that aborts as soon as any of signals does, with its reason. It keeps those signals alive until then.

[ [INSPECT]()

How console.log shows the signal, like Node: AbortSignal { aborted: false }.

class

TimeoutError

#std/task/timeout.vlt:11

Re-exported from velt/task/timeout

class TimeoutError extends AbortError

Thrown by timeout(p, ms) when p does not settle in time, and by throwIfAborted() on a signal that an AbortSignal.timeout aborted.

ms: i64No doc comment yet
constructor(ms: i64)No doc comment yet
type

ScopeOptions

#std/task/scope.vlt:23

Re-exported from velt/task/scope

type ScopeOptions = { cancelOnError?: bool }

taskScope's options. cancelOnError: abort scope.signal when the body or a child fails (default true).

type

SpawnOptions

#std/task/workers.vlt:27

Re-exported from velt/task/workers

type SpawnOptions = { worker?: i64 }

The options of spawn(p, options): worker pins the task to that worker (0 to workerCount() - 1), where it starts and stays.