/skills/fuz-stack/references/async-patterns
  • docs
  • skills
  • fuz-stack
    • Async Patterns
    • Code Generation
    • Common Utilities
    • CSS Patterns
    • Database Query Patterns
    • Dependency Injection
    • Documentation System
    • File Organization
    • mdz — Strict Markdown Dialect
    • Approved npm Dependencies
    • Path References in Documentation
    • Approved Rust Dependencies
    • Rust Patterns for the Fuz Ecosystem
    • Rust Performance Patterns
    • Rust Spine & Consumer Servers
    • Svelte 5 Patterns
    • Task Patterns
    • Testing Patterns
    • TSDoc Comment Style Guide
    • Twin Implementations (TS ↔ Rust)
    • Type Utilities
    • WASM Patterns for the Fuz Ecosystem
    • Zod Schemas
  • grimoire
  • tools
  • hash

Async Patterns

Async concurrency utilities in @fuzdev/fuz_util/async.ts and @fuzdev/fuz_util/dag.ts — controlled concurrency for file I/O, network requests, task execution, and DAG scheduling.

AsyncStatus

Lifecycle type for tracking async operations in UI:

type AsyncStatus = 'initial' | 'pending' | 'success' | 'failure';

Deferred Pattern

Separates promise creation from resolution — external control over when and how a promise resolves. Create with create_deferred():

interface Deferred<T> { promise: Promise<T>; resolve: (value: T) => void; reject: (reason: any) => void; }const deferred = create_deferred<string>(); // Pass the promise to a consumer some_async_consumer(deferred.promise); // Resolve later from the producer deferred.resolve('done');

Used internally by run_dag() and throttle.

Concurrent Operations

Three functions for bounded concurrency over iterables. All require concurrency >= 1, accept an optional AbortSignal, and pass both item and index to fn (which may return synchronously).

Choosing the right function

FunctionReturns resultsFail behaviorUse when
each_concurrentNoFail-fastSide effects only
map_concurrentYes (ordered)Fail-fastTransform + collect
map_concurrent_settledYes (settled)Collects all (no throw)Best-effort collection

Fail-fast (each_concurrent, map_concurrent): on first rejection, stops spawning new workers and rejects — partial results are lost; with signal, aborts immediately.

const results = await map_concurrent( file_paths, 5, // max 5 concurrent reads async (path) => readFile(path, 'utf8') ); // results[i] corresponds to file_paths[i]

Settled (map_concurrent_settled): follows Promise.allSettled — the outer promise never rejects. On abort it resolves with partial results: completed items keep their real settlements, in-flight items reject with the abort reason, and items never pulled from the iterator are absent from the results array.

All three cap in-flight work at concurrency, spawning the next item as each settles. Empty iterables resolve immediately.

AsyncSemaphore

Class-based concurrency limiter — more flexible than concurrent map/each:

const semaphore = new AsyncSemaphore(3); // max 3 concurrent async function do_work(item: string): Promise<void> { await semaphore.acquire(); // blocks if 3 already active try { await process(item); } finally { semaphore.release(); // free the slot } }

Constructor requires permits >= 0.

Infinity permits

new AsyncSemaphore(Infinity) — acquire() always resolves immediately. Useful for disabling concurrency limits without changing call sites.

Used by run_dag() to bound node execution concurrency.

DAG Execution

run_dag() in @fuzdev/fuz_util/dag.ts executes dependency-graph nodes concurrently. Nodes declare dependencies via depends_on; independent nodes run in parallel up to max_concurrency. Uses AsyncSemaphore for concurrency and Deferred for dependency signaling.

import { run_dag, type DagNode } from '@fuzdev/fuz_util/dag.ts'; interface BuildStep extends DagNode { command: string; } const result = await run_dag<BuildStep>({ nodes, execute: async (node) => { await run_command(node.command); }, max_concurrency: 4, stop_on_failure: true // default }); if (!result.success) { console.error(result.error); // e.g., "2 node(s) failed" }

DagNode is {id, depends_on?} extending Sortable (@fuzdev/fuz_util/sort.ts, topological-sort validation). DagOptions adds on_error/on_skip/should_skip hooks, max_concurrency (default Infinity), stop_on_failure (default true), and skip_validation; DagResult aggregates per-node results with counts and duration_ms. Failed dependency nodes cascade — dependents are skipped with reason 'dependency failed'.

Also in async.ts: wait (promise delay), is_promise (thenable guard).