@dcrosstech/dct-ts-utils
v1.1.0
Published
Common TypeScript utilities (sleep, semaphore, queues, heaps, exponential backoff)
Maintainers
Readme
@dcrosstech/dct-ts-utils
A small collection of TypeScript-first async and data-structure utilities, designed to simple and extendible; focused primarily on clean and simple implementations without prerequisites, and simple usese.
This package is ESM-only.
Features
- Cancellable sleep() with remaining-time inspection
- Weighted semaphore with optional priority scheduling
- FIFO and stable priority queues
- Binary heap implementation
- Exponential backoff executor with:
- randomized exponential delay (Ethernet-style windowing)
- retry-state propagation
- explicit terminal failure control
Installation
npm install @dcrosstech/dct-ts-utils
Imports
You can import from the package root:
import { Semaphore, sleep } from "@dcrosstech/dct-ts-utils";
Or import individual modules directly
import { Semaphore } from "@dcrosstech/dct-ts-utils/semaphore"; import { sleep } from "@dcrosstech/dct-ts-utils/sleep"; import { executeWithExponentialBackoff } from "@dcrosstech/dct-ts-utils/retry";
Module Usage Examples
sleep
A cancellable async sleep primitive.
import { sleep } from "@dcrosstech/dct-ts-utils";
const s = sleep(1000);
setTimeout(() => { s.cancel(); }, 100);
try { await s; } catch (e) { // sleep was cancelled }
Available helpers:
- cancel(reason?)
- hasCompleted()
- remainingTime()
Semaphore
A weighted semaphore that runs functions without requiring explicit acquire/release calls.
import { Semaphore } from "@dcrosstech/dct-ts-utils";
const sem = new Semaphore(2);
await Promise.all([ sem.run(async () => { // runs immediately }), sem.run(async () => { // runs immediately }), sem.run(async () => { // queued until capacity is available }), ]);
With weights and priority scheduling:
const sem = new Semaphore(3, { usePriorityQueue: true });
sem.run(workA, { weight: 2, priority: 10 }); sem.run(workB, { weight: 1, priority: 0 });
The semaphore:
- never bypasses the queue head (prevents starvation)
- supports dynamic capacity changes
- allows negative transient counts when adjusting capacity
Queue and FifoQueue
Minimal FIFO queue abstraction.
import { FifoQueue } from "@dcrosstech/dct-ts-utils";
const q = new FifoQueue();
q.enqueue(1); q.enqueue(2);
q.dequeue(); // 1 q.dequeue(); // 2
StablePriorityQueue
A priority queue with FIFO ordering among equal-priority elements.
import { StablePriorityQueue } from "@dcrosstech/dct-ts-utils";
const q = new StablePriorityQueue();
q.enqueue("low", 10); q.enqueue("high", 0); q.enqueue("also-high", 0);
q.dequeue(); // "high" q.dequeue(); // "also-high" q.dequeue(); // "low"
BinaryHeap
An array-backed binary heap with a custom comparator.
import { BinaryHeap } from "@dcrosstech/dct-ts-utils";
const heap = new BinaryHeap((a, b) => a - b);
heap.push(3); heap.push(1); heap.push(2);
heap.pop(); // 1 heap.pop(); // 2
Exponential Backoff Executor
Retry an operation with randomized exponential backoff.
import { executeWithExponentialBackoff, RetryError, TerminalError } from "@dcrosstech/dct-ts-utils/retry";
await executeWithExponentialBackoff( { quantumMs: 10, maxRetries: 5 }, async (state) => { if (state.transientFailure) { throw new RetryError("retrying", nextState(state)); } if (state.fatalFailure) { throw new TerminalError("fatal error"); } return state.result; }, initialState );
Supports:
- unbounded or capped retries
- Ethernet-style randomized backoff windows
- state propagation between retries
- terminal error substitution on retry exhaustion
Semaphore fairness
The semaphore never bypasses the queue head. If the head item cannot run due to insufficient capacity, later items are not allowed to run, even if they would fit.
This prevents starvation and preserves ordering guarantees.
Exponential backoff model
The retry executor uses an Ethernet-style exponential backoff:
- On retry n, choose a random integer in [0 .. factor^k - 1]
- Multiply by a fixed time quantum
- Enforce minimum and optional maximum delay
This avoids thundering-herd behavior while remaining simple and predictable.
Compatibility
- Node.js ≥ 16
- ESM-only (no require() support)
- TypeScript typings included
License
ISC
Author
David Cross https://git.dcrosstech.com/public/dct-ts-utils
