first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,82 @@
# `preload.ts` — bounded-concurrency bulk load
## Purpose
This module implements the bounded-concurrency `preload` algorithm
backing `IrLoader.preload`. It launches up to `concurrency` workers (each
a `while`-loop that pops the next id off a shared cursor), threads the
caller's `AbortSignal` through every per-id load, and produces either a
fully-populated array of `ImpulseResponse` (in input order) on success
or an aggregate `AUDIO_IR_LOADER.DECODE_FAILED` error carrying every
per-id failure on partial failure.
## Features
- Concurrency clamped to `[1, 32]` to prevent caller mistakes from
saturating the runtime.
- Input order preserved on success — the `results` array is indexed by
the id's position in `ids`, not by completion order.
- Aggregate failure: every failing id is collected before the throw, so
callers get a complete picture rather than the first error.
- Abort threading: workers stop launching new loads as soon as
`signal.aborted` becomes true; the throw is `ABORTED` not
`DECODE_FAILED`.
## Usage: Basic
```ts
const irs = await loader.preload(
["club-a", "club-b", "club-c"],
{ concurrency: 2 }
);
```
## Usage: Advanced
The aggregate carries every failure for ergonomic dashboards:
```ts
import {
AUDIO_IR_LOADER_CODES,
AudioIrLoaderError,
} from "@suaveplan/audio-ir-loader";
try {
await loader.preload(ids);
} catch (err) {
if (err instanceof AudioIrLoaderError && err.errors !== undefined) {
for (const { id, error } of err.errors) {
metrics.recordLoadFailure({ id, code: error.code });
}
}
throw err;
}
```
Best-effort callers that want to keep going past failures can call
`Promise.allSettled(ids.map((id) => loader.load(id)))` directly.
## API Reference
### `runPreload(loadFn, ids, options?): Promise<readonly ImpulseResponse[]>`
- `loadFn` — the per-id load function (the loader's closure).
- `ids: readonly string[]` — input ids; order preserved on success.
- `options.signal?: AbortSignal` — shared abort.
- `options.concurrency?: number` — clamped to `[1, 32]`, default `4`.
On full success returns a frozen `ImpulseResponse[]` in input order. On
partial failure throws `AUDIO_IR_LOADER.DECODE_FAILED` with the failure
list on `errors`. On signal abort throws `AUDIO_IR_LOADER.ABORTED`
(carrying any pre-abort failures on `errors`).
## Implementation Notes
The worker pool is a simple "N parallel tasks, all draining a shared
cursor" pattern. The cursor is captured in `takeNext()` which also checks
abort state on entry, so a mid-flight abort halts every worker on its
next iteration. Non-`SuaveplanError` throwables are wrapped as
`AUDIO_IR_LOADER.RESOLVE_FAILED` before being added to the aggregate;
this preserves the invariant that every entry in `errors[]` is a
`SuaveplanError` (and therefore carries a stable `.code`). The success
result is `Object.freeze`d so callers can't mutate the array in place.