first commit
This commit is contained in:
82
docs/media/audio-ir/audio-ir-loader/src/loader/preload.md
Normal file
82
docs/media/audio-ir/audio-ir-loader/src/loader/preload.md
Normal 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.
|
||||
Reference in New Issue
Block a user