React — advanced usage
Escape hatches past the binding layer: connectWorker tuning, per-call abort/timeout, shared observables, and pool lifecycle — same APIs under every framework's idiom.
Tuning the pool
connectWorker folds the WorkerPool config into the client declaration — size, queueing, timeouts, crash respawn.
export const incidents = connectWorker<IncidentsWorker>({
sharedMemory: incidentsMemory,
worker: () => new Worker(
new URL('./incidents.worker.ts', import.meta.url),
{ type: 'module' },
),
poolSize: 'auto', // navigator.hardwareConcurrency
concurrency: 1, // in-flight tasks per worker; excess queue FIFO
maxQueue: 1_000, // a full queue rejects with PoolQueueFullError
respawn: true, // replace crashed workers (default)
taskTimeout: 5_000, // default per-call budget — with({timeout}) overrides
// lazy: false, // spawn immediately instead of on first call
});Abort & timeout per call
with() returns the same client surface with RunOptions attached. A queued call drops outright; an in-flight call is orphaned — the worker finishes it and the reply is discarded.
import { TaskAbortedError, TaskTimeoutError } from '@atolljs/core';
const ac = new AbortController();
const request = incidents
.with({ signal: ac.signal, timeout: 2_000 })
.queryIncidents(query);
ac.abort(); // rejects with TaskAbortedError
try {
await request;
} catch (e) {
if (e instanceof TaskTimeoutError) { /* budget exceeded */ }
}One observable, many components
Each useSharedValue call builds a fresh observe(). Hoist it to module scope and bind via useObservable — every subscriber shares one field watch, which stops when the last unsubscribes.
import { observe, shallowEqual } from '@atolljs/core';
import { useObservable } from '@atolljs/react';
import { incidentsMemory } from '@atolljs/incidents';
export const pressure = observe(
incidentsMemory,
'state.metrics',
(m) => ({ open: m.open, critical: m.critical }),
{ equals: shallowEqual },
);
// In any component: useObservable(pressure) — no new watch per mount.Lifecycle & pool stats
terminate() kills the pool — the next method call re-spawns it lazily. pool.stats() exposes queue/dispatch aggregates for telemetry.
import { useEffect } from 'react';
// A feature panel that only keeps its pool while open:
useEffect(() => () => incidents.terminate(), []);
const stats = incidents.pool?.stats();
// { workers, idle, inFlight, queued, completed, failed, aborted,
// waitMs: { count, mean, max }, runMs: { count, mean, max } }