@vielzeug/familiar 2.2.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -11
- package/dist/_dev.cjs +2 -0
- package/dist/_dev.cjs.map +1 -0
- package/dist/_dev.js +6 -0
- package/dist/_dev.js.map +1 -0
- package/dist/_pool-core.cjs +1 -1
- package/dist/_pool-core.cjs.map +1 -1
- package/dist/_pool-core.d.ts +7 -6
- package/dist/_pool-core.d.ts.map +1 -1
- package/dist/_pool-core.js +80 -67
- package/dist/_pool-core.js.map +1 -1
- package/dist/_pool.cjs +1 -1
- package/dist/_pool.cjs.map +1 -1
- package/dist/_pool.d.ts +8 -5
- package/dist/_pool.d.ts.map +1 -1
- package/dist/_pool.js +116 -109
- package/dist/_pool.js.map +1 -1
- package/dist/_queue.cjs +1 -1
- package/dist/_queue.cjs.map +1 -1
- package/dist/_queue.d.ts +1 -1
- package/dist/_queue.d.ts.map +1 -1
- package/dist/_queue.js +10 -7
- package/dist/_queue.js.map +1 -1
- package/dist/_stream-pool.cjs +1 -1
- package/dist/_stream-pool.cjs.map +1 -1
- package/dist/_stream-pool.d.ts +3 -4
- package/dist/_stream-pool.d.ts.map +1 -1
- package/dist/_stream-pool.js +81 -61
- package/dist/_stream-pool.js.map +1 -1
- package/dist/errors.cjs +1 -1
- package/dist/errors.cjs.map +1 -1
- package/dist/errors.d.ts +8 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +16 -6
- package/dist/errors.js.map +1 -1
- package/dist/familiar.cjs +1 -1
- package/dist/familiar.cjs.map +1 -1
- package/dist/familiar.iife.js +1 -1
- package/dist/familiar.iife.js.map +1 -1
- package/dist/familiar.js +1 -1
- package/dist/familiar.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/protocol.cjs +1 -1
- package/dist/protocol.cjs.map +1 -1
- package/dist/protocol.d.ts +1 -0
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +16 -5
- package/dist/protocol.js.map +1 -1
- package/dist/testing/index.d.ts +1 -1
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/testing.cjs +1 -1
- package/dist/testing/testing.cjs.map +1 -1
- package/dist/testing/testing.d.ts +3 -3
- package/dist/testing/testing.d.ts.map +1 -1
- package/dist/testing/testing.js +25 -24
- package/dist/testing/testing.js.map +1 -1
- package/dist/types.d.ts +2 -15
- package/dist/types.d.ts.map +1 -1
- package/dist/worker.cjs +1 -1
- package/dist/worker.cjs.map +1 -1
- package/dist/worker.d.ts +5 -4
- package/dist/worker.d.ts.map +1 -1
- package/dist/worker.js +49 -38
- package/dist/worker.js.map +1 -1
- package/package.json +10 -8
package/README.md
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# @vielzeug/familiar
|
|
2
2
|
|
|
3
|
-
>
|
|
4
|
-
|
|
5
|
-
`@vielzeug/familiar` runs typed work in ES module workers. Worker modules keep imports, source maps, and normal file boundaries intact.
|
|
3
|
+
> Web Worker pool with tasks, timeouts, cancellation
|
|
6
4
|
|
|
7
5
|
## Installation
|
|
8
6
|
|
|
9
7
|
```sh
|
|
10
8
|
pnpm add @vielzeug/familiar
|
|
9
|
+
npm install @vielzeug/familiar
|
|
10
|
+
yarn add @vielzeug/familiar
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
## Quick Start
|
|
@@ -35,20 +35,13 @@ try {
|
|
|
35
35
|
}
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
-
## Exports
|
|
39
|
-
|
|
40
|
-
- `createWorker()` creates a task pool backed by modules registered with `exposeTask()`.
|
|
41
|
-
- `createStreamWorker()` creates a stream-only pool backed by modules registered with `exposeStream()`.
|
|
42
|
-
- `batch()` and `createTaskGroup()` compose task-pool work without widening every pool handle.
|
|
43
|
-
- `createTestWorker()` provides structured-clone, timeout, cancellation, and error-wrapping parity for task-pool tests.
|
|
44
|
-
- `dispose()` stops work immediately; `drain()` waits for active work before teardown.
|
|
45
|
-
|
|
46
38
|
## Documentation
|
|
47
39
|
|
|
48
40
|
- [Overview](https://vielzeug.dev/familiar/)
|
|
49
41
|
- [Usage Guide](https://vielzeug.dev/familiar/usage)
|
|
50
42
|
- [API Reference](https://vielzeug.dev/familiar/api)
|
|
51
43
|
- [Examples](https://vielzeug.dev/familiar/examples)
|
|
44
|
+
- [Migration Guide](https://vielzeug.dev/familiar/migration)
|
|
52
45
|
|
|
53
46
|
## License
|
|
54
47
|
|
package/dist/_dev.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_dev.cjs","names":[],"sources":["../src/_dev.ts"],"sourcesContent":["const isDev = !(globalThis as { __FAMILIAR_PROD__?: boolean }).__FAMILIAR_PROD__;\n\n/** @internal */\nexport function warn(msg: string): void {\n if (isDev) console.warn(`[@vielzeug/familiar] ${msg}`);\n}\n\n/** @internal — Run fn only in dev builds. Use when dev-only logic goes beyond a single warn() / error() call. */\nexport function devOnly(fn: () => void): void {\n if (isDev) fn();\n}\n"],"mappings":"AAGA,SAAgB,EAAK,EAAmB,CAExC"}
|
package/dist/_dev.js
ADDED
package/dist/_dev.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_dev.js","names":[],"sources":["../src/_dev.ts"],"sourcesContent":["const isDev = !(globalThis as { __FAMILIAR_PROD__?: boolean }).__FAMILIAR_PROD__;\n\n/** @internal */\nexport function warn(msg: string): void {\n if (isDev) console.warn(`[@vielzeug/familiar] ${msg}`);\n}\n\n/** @internal — Run fn only in dev builds. Use when dev-only logic goes beyond a single warn() / error() call. */\nexport function devOnly(fn: () => void): void {\n if (isDev) fn();\n}\n"],"mappings":";AAGA,SAAgB,EAAK,GAAmB,CAExC"}
|
package/dist/_pool-core.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("./_timers.cjs"),t=require("./errors.cjs");let n=require("@vielzeug/arsenal
|
|
1
|
+
const e=require("./_timers.cjs"),t=require("./errors.cjs");let n=require("@vielzeug/arsenal");var r=2147483647;function i(e){if(!Number.isFinite(e))throw new t.FamiliarInvalidOptionsError("`priority` must be a finite number");return e}function a(e,n=`timeout`){if(e!==void 0&&(!Number.isInteger(e)||e<1||e>2147483647))throw new t.FamiliarInvalidOptionsError(`\`${n}\` must be an integer from 1 through ${r}`);return e}function o(r){let i=new AbortController,o=[],s=[],c=0,l=0,u=0,d=0,f,p=!1;function m(){if(r.isIdle())for(let e of o.splice(0))e.timer&&clearTimeout(e.timer),e.resolve()}function h(n){return r.isIdle()?Promise.resolve():new Promise((r,i)=>{let a={reject:i,resolve:r};n.timeout!==void 0&&(a.timer=setTimeout(()=>{let e=o.indexOf(a);e!==-1&&o.splice(e,1),i(new t.FamiliarTimeoutError(n.timeout,`Drain`))},n.timeout),e.unrefTimer(a.timer)),o.push(a)})}function g(){s.shift()?.resolve()}function _(e){for(let t of s.splice(0))t.reject(e)}function v(e,t){return e?.aborted?Promise.reject((0,n.abortError)(e)):new Promise((r,i)=>{let a=!1,o={cleanup(){e?.removeEventListener(`abort`,c)},priority:t,reject(e){if(a)return;a=!0,o.cleanup();let t=s.indexOf(o);t!==-1&&s.splice(t,1),i(e)},resolve(){a||(a=!0,o.cleanup(),r())},sequence:l++},c=()=>o.reject((0,n.abortError)(e));e?.addEventListener(`abort`,c,{once:!0}),s.push(o),s.sort((e,t)=>t.priority-e.priority||e.sequence-t.sequence)})}function y(){p||(p=!0,i.abort(),r.onDispose(),_(new t.FamiliarTerminatedError),m())}function b(e={}){if(p)return Promise.resolve();try{a(e.timeout,`drain.timeout`)}catch(e){return Promise.reject(e)}return f||(r.onDrainStart(),_(new t.FamiliarTerminatedError(`Worker is draining`)),f=h(e).then(()=>y(),e=>{throw y(),e}),f)}function x(e){c+=e}function S(){u+=1}function C(){d+=1}function w(e){return{active:c,completed:u,failed:d,queued:e+s.length}}function T(){return p?`terminated`:c===0?`idle`:`running`}return{disposalSignal:i.signal,dispose:y,get disposed(){return p},drain:b,get drainPromise(){return f},isIdle:r.isIdle,rejectCapacity:_,releaseCapacity:g,settleIdle:m,stats:w,status:T,trackActive:x,trackCompleted:S,trackFailed:C,waitForCapacity:v,waitForIdle:h}}exports.MAX_TIMEOUT=r,exports.createPoolCore=o,exports.validatePriority=i,exports.validateTimeout=a;
|
|
2
2
|
//# sourceMappingURL=_pool-core.cjs.map
|
package/dist/_pool-core.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_pool-core.cjs","names":[],"sources":["../src/_pool-core.ts"],"sourcesContent":["import { abortError } from '@vielzeug/arsenal
|
|
1
|
+
{"version":3,"file":"_pool-core.cjs","names":[],"sources":["../src/_pool-core.ts"],"sourcesContent":["import { abortError } from '@vielzeug/arsenal';\nimport { unrefTimer } from './_timers.js';\nimport { FamiliarInvalidOptionsError, FamiliarTerminatedError, FamiliarTimeoutError } from './errors.js';\nimport type { DrainOptions, WorkerStats, WorkerStatus } from './types.js';\n\nexport const MAX_CONCURRENCY = 512;\nexport const MAX_TIMEOUT = 2_147_483_647;\n\nexport function validatePriority(priority: number): number {\n if (!Number.isFinite(priority)) throw new FamiliarInvalidOptionsError('`priority` must be a finite number');\n return priority;\n}\n\nexport function validateTimeout(timeout: number | undefined, name = 'timeout'): number | undefined {\n if (timeout !== undefined && (!Number.isInteger(timeout) || timeout < 1 || timeout > MAX_TIMEOUT)) {\n throw new FamiliarInvalidOptionsError(`\\`${name}\\` must be an integer from 1 through ${MAX_TIMEOUT}`);\n }\n return timeout;\n}\n\nexport type PoolOptions = {\n concurrency: number;\n defaultTimeout: number | undefined;\n maxQueue: number | undefined;\n onFull: 'reject' | 'wait';\n};\n\ntype IdleWaiter = {\n reject: (reason: unknown) => void;\n resolve: () => void;\n timer?: ReturnType<typeof setTimeout>;\n};\n\ntype CapacityWaiter = {\n cleanup(): void;\n priority: number;\n reject(reason: unknown): void;\n resolve(): void;\n sequence: number;\n};\n\nexport interface PoolCore {\n readonly disposalSignal: AbortSignal;\n dispose(): void;\n readonly disposed: boolean;\n drain(options?: DrainOptions): Promise<void>;\n readonly drainPromise: Promise<void> | undefined;\n isIdle(): boolean;\n rejectCapacity(reason: unknown): void;\n releaseCapacity(): void;\n settleIdle(): void;\n stats(queued: number): WorkerStats;\n status(): WorkerStatus;\n trackActive(delta: number): void;\n trackCompleted(): void;\n trackFailed(): void;\n waitForCapacity(signal: AbortSignal | undefined, priority: number): Promise<void>;\n waitForIdle(options: DrainOptions): Promise<void>;\n}\n\n/**\n * Shared disposal controller, idle/capacity waiters, drain, and stats tracking\n * used by both the single-result pool (`_pool.ts`) and the stream pool\n * (`_stream-pool.ts`). Each pool provides its own `isIdle` predicate and\n * `onDispose`/`onDrainStart` hooks to flush pool-specific pending work.\n */\nexport function createPoolCore(options: {\n isIdle: () => boolean;\n onDispose: () => void;\n onDrainStart: () => void;\n}): PoolCore {\n const disposalController = new AbortController();\n const idleWaiters: IdleWaiter[] = [];\n const capacityWaiters: CapacityWaiter[] = [];\n let active = 0;\n let capacitySequence = 0;\n let completed = 0;\n let failed = 0;\n let drainPromise: Promise<void> | undefined;\n let terminated = false;\n\n function settleIdle(): void {\n if (!options.isIdle()) return;\n\n for (const waiter of idleWaiters.splice(0)) {\n if (waiter.timer) clearTimeout(waiter.timer);\n\n waiter.resolve();\n }\n }\n\n function waitForIdle(drainOptions: DrainOptions): Promise<void> {\n if (options.isIdle()) return Promise.resolve();\n\n return new Promise<void>((resolve, reject) => {\n const waiter: IdleWaiter = { reject, resolve };\n\n if (drainOptions.timeout !== undefined) {\n waiter.timer = setTimeout(() => {\n const index = idleWaiters.indexOf(waiter);\n\n if (index !== -1) idleWaiters.splice(index, 1);\n\n reject(new FamiliarTimeoutError(drainOptions.timeout!, 'Drain'));\n }, drainOptions.timeout);\n unrefTimer(waiter.timer);\n }\n\n idleWaiters.push(waiter);\n });\n }\n\n function releaseCapacity(): void {\n capacityWaiters.shift()?.resolve();\n }\n\n function rejectCapacity(reason: unknown): void {\n for (const waiter of capacityWaiters.splice(0)) waiter.reject(reason);\n }\n\n function waitForCapacity(signal: AbortSignal | undefined, priority: number): Promise<void> {\n if (signal?.aborted) return Promise.reject(abortError(signal));\n\n return new Promise<void>((resolve, reject) => {\n let settled = false;\n const waiter: CapacityWaiter = {\n cleanup() {\n signal?.removeEventListener('abort', onAbort);\n },\n priority,\n reject(reason) {\n if (settled) return;\n\n settled = true;\n waiter.cleanup();\n\n const index = capacityWaiters.indexOf(waiter);\n\n if (index !== -1) capacityWaiters.splice(index, 1);\n\n reject(reason);\n },\n resolve() {\n if (settled) return;\n\n settled = true;\n waiter.cleanup();\n resolve();\n },\n sequence: capacitySequence++,\n };\n const onAbort = () => waiter.reject(abortError(signal!));\n\n signal?.addEventListener('abort', onAbort, { once: true });\n capacityWaiters.push(waiter);\n capacityWaiters.sort((a, b) => b.priority - a.priority || a.sequence - b.sequence);\n });\n }\n\n function dispose(): void {\n if (terminated) return;\n\n terminated = true;\n disposalController.abort();\n options.onDispose();\n rejectCapacity(new FamiliarTerminatedError());\n settleIdle();\n }\n\n function drain(drainOptions: DrainOptions = {}): Promise<void> {\n if (terminated) return Promise.resolve();\n try {\n validateTimeout(drainOptions.timeout, 'drain.timeout');\n } catch (error) {\n return Promise.reject(error);\n }\n\n if (drainPromise) return drainPromise;\n\n options.onDrainStart();\n rejectCapacity(new FamiliarTerminatedError('Worker is draining'));\n drainPromise = waitForIdle(drainOptions).then(\n () => dispose(),\n (error: unknown) => {\n dispose();\n throw error;\n },\n );\n\n return drainPromise;\n }\n\n function trackActive(delta: number): void {\n active += delta;\n }\n\n function trackCompleted(): void {\n completed += 1;\n }\n\n function trackFailed(): void {\n failed += 1;\n }\n\n function stats(queued: number): WorkerStats {\n return { active, completed, failed, queued: queued + capacityWaiters.length };\n }\n\n function status(): WorkerStatus {\n if (terminated) return 'terminated';\n\n return active === 0 ? 'idle' : 'running';\n }\n\n return {\n disposalSignal: disposalController.signal,\n dispose,\n get disposed() {\n return terminated;\n },\n drain,\n get drainPromise() {\n return drainPromise;\n },\n isIdle: options.isIdle,\n rejectCapacity,\n releaseCapacity,\n settleIdle,\n stats,\n status,\n trackActive,\n trackCompleted,\n trackFailed,\n waitForCapacity,\n waitForIdle,\n };\n}\n"],"mappings":"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"}
|
package/dist/_pool-core.d.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import type { DrainOptions, WorkerStats, WorkerStatus } from './types';
|
|
1
|
+
import type { DrainOptions, WorkerStats, WorkerStatus } from './types.js';
|
|
2
|
+
export declare const MAX_CONCURRENCY = 512;
|
|
3
|
+
export declare const MAX_TIMEOUT = 2147483647;
|
|
4
|
+
export declare function validatePriority(priority: number): number;
|
|
5
|
+
export declare function validateTimeout(timeout: number | undefined, name?: string): number | undefined;
|
|
2
6
|
export type PoolOptions = {
|
|
3
7
|
concurrency: number;
|
|
4
8
|
defaultTimeout: number | undefined;
|
|
@@ -9,12 +13,9 @@ export interface PoolCore {
|
|
|
9
13
|
readonly disposalSignal: AbortSignal;
|
|
10
14
|
dispose(): void;
|
|
11
15
|
readonly disposed: boolean;
|
|
12
|
-
drain(options
|
|
16
|
+
drain(options?: DrainOptions): Promise<void>;
|
|
13
17
|
readonly drainPromise: Promise<void> | undefined;
|
|
14
18
|
isIdle(): boolean;
|
|
15
|
-
prime(slots: readonly {
|
|
16
|
-
prime(): Promise<void>;
|
|
17
|
-
}[]): Promise<void>;
|
|
18
19
|
rejectCapacity(reason: unknown): void;
|
|
19
20
|
releaseCapacity(): void;
|
|
20
21
|
settleIdle(): void;
|
|
@@ -23,7 +24,7 @@ export interface PoolCore {
|
|
|
23
24
|
trackActive(delta: number): void;
|
|
24
25
|
trackCompleted(): void;
|
|
25
26
|
trackFailed(): void;
|
|
26
|
-
waitForCapacity(signal: AbortSignal | undefined): Promise<void>;
|
|
27
|
+
waitForCapacity(signal: AbortSignal | undefined, priority: number): Promise<void>;
|
|
27
28
|
waitForIdle(options: DrainOptions): Promise<void>;
|
|
28
29
|
}
|
|
29
30
|
/**
|
package/dist/_pool-core.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_pool-core.d.ts","sourceRoot":"","sources":["../src/_pool-core.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"_pool-core.d.ts","sourceRoot":"","sources":["../src/_pool-core.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1E,eAAO,MAAM,eAAe,MAAM,CAAC;AACnC,eAAO,MAAM,WAAW,aAAgB,CAAC;AAEzC,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGzD;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,SAAY,GAAG,MAAM,GAAG,SAAS,CAKjG;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,MAAM,EAAE,QAAQ,GAAG,MAAM,CAAC;CAC3B,CAAC;AAgBF,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,cAAc,EAAE,WAAW,CAAC;IACrC,OAAO,IAAI,IAAI,CAAC;IAChB,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,KAAK,CAAC,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC;IACjD,MAAM,IAAI,OAAO,CAAC;IAClB,cAAc,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC;IACtC,eAAe,IAAI,IAAI,CAAC;IACxB,UAAU,IAAI,IAAI,CAAC;IACnB,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,CAAC;IACnC,MAAM,IAAI,YAAY,CAAC;IACvB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,cAAc,IAAI,IAAI,CAAC;IACvB,WAAW,IAAI,IAAI,CAAC;IACpB,eAAe,CAAC,MAAM,EAAE,WAAW,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClF,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnD;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE;IACtC,MAAM,EAAE,MAAM,OAAO,CAAC;IACtB,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,YAAY,EAAE,MAAM,IAAI,CAAC;CAC1B,GAAG,QAAQ,CAsKX"}
|
package/dist/_pool-core.js
CHANGED
|
@@ -1,105 +1,118 @@
|
|
|
1
1
|
import { unrefTimer as e } from "./_timers.js";
|
|
2
|
-
import {
|
|
3
|
-
import { abortError as
|
|
2
|
+
import { FamiliarInvalidOptionsError as t, FamiliarTerminatedError as n, FamiliarTimeoutError as r } from "./errors.js";
|
|
3
|
+
import { abortError as i } from "@vielzeug/arsenal";
|
|
4
4
|
//#region src/_pool-core.ts
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
var a = 2147483647;
|
|
6
|
+
function o(e) {
|
|
7
|
+
if (!Number.isFinite(e)) throw new t("`priority` must be a finite number");
|
|
8
|
+
return e;
|
|
9
|
+
}
|
|
10
|
+
function s(e, n = "timeout") {
|
|
11
|
+
if (e !== void 0 && (!Number.isInteger(e) || e < 1 || e > 2147483647)) throw new t(`\`${n}\` must be an integer from 1 through ${a}`);
|
|
12
|
+
return e;
|
|
13
|
+
}
|
|
14
|
+
function c(t) {
|
|
15
|
+
let a = new AbortController(), o = [], c = [], l = 0, u = 0, d = 0, f = 0, p, m = !1;
|
|
16
|
+
function h() {
|
|
17
|
+
if (t.isIdle()) for (let e of o.splice(0)) e.timer && clearTimeout(e.timer), e.resolve();
|
|
9
18
|
}
|
|
10
|
-
function
|
|
11
|
-
return
|
|
19
|
+
function g(n) {
|
|
20
|
+
return t.isIdle() ? Promise.resolve() : new Promise((t, i) => {
|
|
12
21
|
let a = {
|
|
13
22
|
reject: i,
|
|
14
|
-
resolve:
|
|
23
|
+
resolve: t
|
|
15
24
|
};
|
|
16
|
-
|
|
25
|
+
n.timeout !== void 0 && (a.timer = setTimeout(() => {
|
|
17
26
|
let e = o.indexOf(a);
|
|
18
|
-
e !== -1 && o.splice(e, 1), i(new n
|
|
19
|
-
},
|
|
27
|
+
e !== -1 && o.splice(e, 1), i(new r(n.timeout, "Drain"));
|
|
28
|
+
}, n.timeout), e(a.timer)), o.push(a);
|
|
20
29
|
});
|
|
21
30
|
}
|
|
22
|
-
function
|
|
23
|
-
|
|
31
|
+
function _() {
|
|
32
|
+
c.shift()?.resolve();
|
|
24
33
|
}
|
|
25
|
-
function
|
|
26
|
-
for (let t of
|
|
34
|
+
function v(e) {
|
|
35
|
+
for (let t of c.splice(0)) t.reject(e);
|
|
27
36
|
}
|
|
28
|
-
function
|
|
29
|
-
return e?.aborted ? Promise.reject(
|
|
30
|
-
let
|
|
37
|
+
function y(e, t) {
|
|
38
|
+
return e?.aborted ? Promise.reject(i(e)) : new Promise((n, r) => {
|
|
39
|
+
let a = !1, o = {
|
|
31
40
|
cleanup() {
|
|
32
|
-
e?.removeEventListener("abort",
|
|
41
|
+
e?.removeEventListener("abort", s);
|
|
33
42
|
},
|
|
43
|
+
priority: t,
|
|
34
44
|
reject(e) {
|
|
35
|
-
if (
|
|
36
|
-
|
|
37
|
-
let t =
|
|
38
|
-
t !== -1 &&
|
|
45
|
+
if (a) return;
|
|
46
|
+
a = !0, o.cleanup();
|
|
47
|
+
let t = c.indexOf(o);
|
|
48
|
+
t !== -1 && c.splice(t, 1), r(e);
|
|
39
49
|
},
|
|
40
50
|
resolve() {
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
|
|
51
|
+
a || (a = !0, o.cleanup(), n());
|
|
52
|
+
},
|
|
53
|
+
sequence: u++
|
|
54
|
+
}, s = () => o.reject(i(e));
|
|
55
|
+
e?.addEventListener("abort", s, { once: !0 }), c.push(o), c.sort((e, t) => t.priority - e.priority || e.sequence - t.sequence);
|
|
45
56
|
});
|
|
46
57
|
}
|
|
47
|
-
function
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
function y(e) {
|
|
51
|
-
return f ? Promise.resolve() : d || (i.onDrainStart(), g(new t("Worker is draining")), d = m(e).then(() => v(), (e) => {
|
|
52
|
-
throw v(), e;
|
|
53
|
-
}), d);
|
|
58
|
+
function b() {
|
|
59
|
+
m || (m = !0, a.abort(), t.onDispose(), v(new n()), h());
|
|
54
60
|
}
|
|
55
|
-
function
|
|
56
|
-
|
|
61
|
+
function x(e = {}) {
|
|
62
|
+
if (m) return Promise.resolve();
|
|
63
|
+
try {
|
|
64
|
+
s(e.timeout, "drain.timeout");
|
|
65
|
+
} catch (e) {
|
|
66
|
+
return Promise.reject(e);
|
|
67
|
+
}
|
|
68
|
+
return p || (t.onDrainStart(), v(new n("Worker is draining")), p = g(e).then(() => b(), (e) => {
|
|
69
|
+
throw b(), e;
|
|
70
|
+
}), p);
|
|
57
71
|
}
|
|
58
|
-
function
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
function S() {
|
|
62
|
-
l += 1;
|
|
72
|
+
function S(e) {
|
|
73
|
+
l += e;
|
|
63
74
|
}
|
|
64
75
|
function C() {
|
|
65
|
-
|
|
76
|
+
d += 1;
|
|
77
|
+
}
|
|
78
|
+
function w() {
|
|
79
|
+
f += 1;
|
|
66
80
|
}
|
|
67
|
-
function
|
|
81
|
+
function T(e) {
|
|
68
82
|
return {
|
|
69
|
-
active:
|
|
70
|
-
completed:
|
|
71
|
-
failed:
|
|
72
|
-
queued: e
|
|
83
|
+
active: l,
|
|
84
|
+
completed: d,
|
|
85
|
+
failed: f,
|
|
86
|
+
queued: e + c.length
|
|
73
87
|
};
|
|
74
88
|
}
|
|
75
|
-
function
|
|
76
|
-
return
|
|
89
|
+
function E() {
|
|
90
|
+
return m ? "terminated" : l === 0 ? "idle" : "running";
|
|
77
91
|
}
|
|
78
92
|
return {
|
|
79
93
|
disposalSignal: a.signal,
|
|
80
|
-
dispose:
|
|
94
|
+
dispose: b,
|
|
81
95
|
get disposed() {
|
|
82
|
-
return
|
|
96
|
+
return m;
|
|
83
97
|
},
|
|
84
|
-
drain:
|
|
98
|
+
drain: x,
|
|
85
99
|
get drainPromise() {
|
|
86
|
-
return
|
|
100
|
+
return p;
|
|
87
101
|
},
|
|
88
|
-
isIdle:
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
waitForIdle: m
|
|
102
|
+
isIdle: t.isIdle,
|
|
103
|
+
rejectCapacity: v,
|
|
104
|
+
releaseCapacity: _,
|
|
105
|
+
settleIdle: h,
|
|
106
|
+
stats: T,
|
|
107
|
+
status: E,
|
|
108
|
+
trackActive: S,
|
|
109
|
+
trackCompleted: C,
|
|
110
|
+
trackFailed: w,
|
|
111
|
+
waitForCapacity: y,
|
|
112
|
+
waitForIdle: g
|
|
100
113
|
};
|
|
101
114
|
}
|
|
102
115
|
//#endregion
|
|
103
|
-
export {
|
|
116
|
+
export { a as MAX_TIMEOUT, c as createPoolCore, o as validatePriority, s as validateTimeout };
|
|
104
117
|
|
|
105
118
|
//# sourceMappingURL=_pool-core.js.map
|
package/dist/_pool-core.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_pool-core.js","names":[],"sources":["../src/_pool-core.ts"],"sourcesContent":["import { abortError } from '@vielzeug/arsenal
|
|
1
|
+
{"version":3,"file":"_pool-core.js","names":[],"sources":["../src/_pool-core.ts"],"sourcesContent":["import { abortError } from '@vielzeug/arsenal';\nimport { unrefTimer } from './_timers.js';\nimport { FamiliarInvalidOptionsError, FamiliarTerminatedError, FamiliarTimeoutError } from './errors.js';\nimport type { DrainOptions, WorkerStats, WorkerStatus } from './types.js';\n\nexport const MAX_CONCURRENCY = 512;\nexport const MAX_TIMEOUT = 2_147_483_647;\n\nexport function validatePriority(priority: number): number {\n if (!Number.isFinite(priority)) throw new FamiliarInvalidOptionsError('`priority` must be a finite number');\n return priority;\n}\n\nexport function validateTimeout(timeout: number | undefined, name = 'timeout'): number | undefined {\n if (timeout !== undefined && (!Number.isInteger(timeout) || timeout < 1 || timeout > MAX_TIMEOUT)) {\n throw new FamiliarInvalidOptionsError(`\\`${name}\\` must be an integer from 1 through ${MAX_TIMEOUT}`);\n }\n return timeout;\n}\n\nexport type PoolOptions = {\n concurrency: number;\n defaultTimeout: number | undefined;\n maxQueue: number | undefined;\n onFull: 'reject' | 'wait';\n};\n\ntype IdleWaiter = {\n reject: (reason: unknown) => void;\n resolve: () => void;\n timer?: ReturnType<typeof setTimeout>;\n};\n\ntype CapacityWaiter = {\n cleanup(): void;\n priority: number;\n reject(reason: unknown): void;\n resolve(): void;\n sequence: number;\n};\n\nexport interface PoolCore {\n readonly disposalSignal: AbortSignal;\n dispose(): void;\n readonly disposed: boolean;\n drain(options?: DrainOptions): Promise<void>;\n readonly drainPromise: Promise<void> | undefined;\n isIdle(): boolean;\n rejectCapacity(reason: unknown): void;\n releaseCapacity(): void;\n settleIdle(): void;\n stats(queued: number): WorkerStats;\n status(): WorkerStatus;\n trackActive(delta: number): void;\n trackCompleted(): void;\n trackFailed(): void;\n waitForCapacity(signal: AbortSignal | undefined, priority: number): Promise<void>;\n waitForIdle(options: DrainOptions): Promise<void>;\n}\n\n/**\n * Shared disposal controller, idle/capacity waiters, drain, and stats tracking\n * used by both the single-result pool (`_pool.ts`) and the stream pool\n * (`_stream-pool.ts`). Each pool provides its own `isIdle` predicate and\n * `onDispose`/`onDrainStart` hooks to flush pool-specific pending work.\n */\nexport function createPoolCore(options: {\n isIdle: () => boolean;\n onDispose: () => void;\n onDrainStart: () => void;\n}): PoolCore {\n const disposalController = new AbortController();\n const idleWaiters: IdleWaiter[] = [];\n const capacityWaiters: CapacityWaiter[] = [];\n let active = 0;\n let capacitySequence = 0;\n let completed = 0;\n let failed = 0;\n let drainPromise: Promise<void> | undefined;\n let terminated = false;\n\n function settleIdle(): void {\n if (!options.isIdle()) return;\n\n for (const waiter of idleWaiters.splice(0)) {\n if (waiter.timer) clearTimeout(waiter.timer);\n\n waiter.resolve();\n }\n }\n\n function waitForIdle(drainOptions: DrainOptions): Promise<void> {\n if (options.isIdle()) return Promise.resolve();\n\n return new Promise<void>((resolve, reject) => {\n const waiter: IdleWaiter = { reject, resolve };\n\n if (drainOptions.timeout !== undefined) {\n waiter.timer = setTimeout(() => {\n const index = idleWaiters.indexOf(waiter);\n\n if (index !== -1) idleWaiters.splice(index, 1);\n\n reject(new FamiliarTimeoutError(drainOptions.timeout!, 'Drain'));\n }, drainOptions.timeout);\n unrefTimer(waiter.timer);\n }\n\n idleWaiters.push(waiter);\n });\n }\n\n function releaseCapacity(): void {\n capacityWaiters.shift()?.resolve();\n }\n\n function rejectCapacity(reason: unknown): void {\n for (const waiter of capacityWaiters.splice(0)) waiter.reject(reason);\n }\n\n function waitForCapacity(signal: AbortSignal | undefined, priority: number): Promise<void> {\n if (signal?.aborted) return Promise.reject(abortError(signal));\n\n return new Promise<void>((resolve, reject) => {\n let settled = false;\n const waiter: CapacityWaiter = {\n cleanup() {\n signal?.removeEventListener('abort', onAbort);\n },\n priority,\n reject(reason) {\n if (settled) return;\n\n settled = true;\n waiter.cleanup();\n\n const index = capacityWaiters.indexOf(waiter);\n\n if (index !== -1) capacityWaiters.splice(index, 1);\n\n reject(reason);\n },\n resolve() {\n if (settled) return;\n\n settled = true;\n waiter.cleanup();\n resolve();\n },\n sequence: capacitySequence++,\n };\n const onAbort = () => waiter.reject(abortError(signal!));\n\n signal?.addEventListener('abort', onAbort, { once: true });\n capacityWaiters.push(waiter);\n capacityWaiters.sort((a, b) => b.priority - a.priority || a.sequence - b.sequence);\n });\n }\n\n function dispose(): void {\n if (terminated) return;\n\n terminated = true;\n disposalController.abort();\n options.onDispose();\n rejectCapacity(new FamiliarTerminatedError());\n settleIdle();\n }\n\n function drain(drainOptions: DrainOptions = {}): Promise<void> {\n if (terminated) return Promise.resolve();\n try {\n validateTimeout(drainOptions.timeout, 'drain.timeout');\n } catch (error) {\n return Promise.reject(error);\n }\n\n if (drainPromise) return drainPromise;\n\n options.onDrainStart();\n rejectCapacity(new FamiliarTerminatedError('Worker is draining'));\n drainPromise = waitForIdle(drainOptions).then(\n () => dispose(),\n (error: unknown) => {\n dispose();\n throw error;\n },\n );\n\n return drainPromise;\n }\n\n function trackActive(delta: number): void {\n active += delta;\n }\n\n function trackCompleted(): void {\n completed += 1;\n }\n\n function trackFailed(): void {\n failed += 1;\n }\n\n function stats(queued: number): WorkerStats {\n return { active, completed, failed, queued: queued + capacityWaiters.length };\n }\n\n function status(): WorkerStatus {\n if (terminated) return 'terminated';\n\n return active === 0 ? 'idle' : 'running';\n }\n\n return {\n disposalSignal: disposalController.signal,\n dispose,\n get disposed() {\n return terminated;\n },\n drain,\n get drainPromise() {\n return drainPromise;\n },\n isIdle: options.isIdle,\n rejectCapacity,\n releaseCapacity,\n settleIdle,\n stats,\n status,\n trackActive,\n trackCompleted,\n trackFailed,\n waitForCapacity,\n waitForIdle,\n };\n}\n"],"mappings":";;;;AAMA,IAAa,IAAc;AAE3B,SAAgB,EAAiB,GAA0B;CACzD,IAAI,CAAC,OAAO,SAAS,CAAQ,GAAG,MAAM,IAAI,EAA4B,oCAAoC;CAC1G,OAAO;AACT;AAEA,SAAgB,EAAgB,GAA6B,IAAO,WAA+B;CACjG,IAAI,MAAY,KAAA,MAAc,CAAC,OAAO,UAAU,CAAO,KAAK,IAAU,KAAK,IAAA,aACzE,MAAM,IAAI,EAA4B,KAAK,EAAK,uCAAuC,GAAa;CAEtG,OAAO;AACT;AAgDA,SAAgB,EAAe,GAIlB;CACX,IAAM,IAAqB,IAAI,gBAAgB,GACzC,IAA4B,CAAC,GAC7B,IAAoC,CAAC,GACvC,IAAS,GACT,IAAmB,GACnB,IAAY,GACZ,IAAS,GACT,GACA,IAAa;CAEjB,SAAS,IAAmB;EACrB,MAAQ,OAAO,GAEpB,KAAK,IAAM,KAAU,EAAY,OAAO,CAAC,GAGvC,AAFI,EAAO,SAAO,aAAa,EAAO,KAAK,GAE3C,EAAO,QAAQ;CAEnB;CAEA,SAAS,EAAY,GAA2C;EAG9D,OAFI,EAAQ,OAAO,IAAU,QAAQ,QAAQ,IAEtC,IAAI,SAAe,GAAS,MAAW;GAC5C,IAAM,IAAqB;IAAE;IAAQ;GAAQ;GAa7C,AAXI,EAAa,YAAY,KAAA,MAC3B,EAAO,QAAQ,iBAAiB;IAC9B,IAAM,IAAQ,EAAY,QAAQ,CAAM;IAIxC,AAFI,MAAU,MAAI,EAAY,OAAO,GAAO,CAAC,GAE7C,EAAO,IAAI,EAAqB,EAAa,SAAU,OAAO,CAAC;GACjE,GAAG,EAAa,OAAO,GACvB,EAAW,EAAO,KAAK,IAGzB,EAAY,KAAK,CAAM;EACzB,CAAC;CACH;CAEA,SAAS,IAAwB;EAC/B,EAAgB,MAAM,CAAC,EAAE,QAAQ;CACnC;CAEA,SAAS,EAAe,GAAuB;EAC7C,KAAK,IAAM,KAAU,EAAgB,OAAO,CAAC,GAAG,EAAO,OAAO,CAAM;CACtE;CAEA,SAAS,EAAgB,GAAiC,GAAiC;EAGzF,OAFI,GAAQ,UAAgB,QAAQ,OAAO,EAAW,CAAM,CAAC,IAEtD,IAAI,SAAe,GAAS,MAAW;GAC5C,IAAI,IAAU,IACR,IAAyB;IAC7B,UAAU;KACR,GAAQ,oBAAoB,SAAS,CAAO;IAC9C;IACA;IACA,OAAO,GAAQ;KACb,IAAI,GAAS;KAGb,AADA,IAAU,IACV,EAAO,QAAQ;KAEf,IAAM,IAAQ,EAAgB,QAAQ,CAAM;KAI5C,AAFI,MAAU,MAAI,EAAgB,OAAO,GAAO,CAAC,GAEjD,EAAO,CAAM;IACf;IACA,UAAU;KACJ,MAEJ,IAAU,IACV,EAAO,QAAQ,GACf,EAAQ;IACV;IACA,UAAU;GACZ,GACM,UAAgB,EAAO,OAAO,EAAW,CAAO,CAAC;GAIvD,AAFA,GAAQ,iBAAiB,SAAS,GAAS,EAAE,MAAM,GAAK,CAAC,GACzD,EAAgB,KAAK,CAAM,GAC3B,EAAgB,MAAM,GAAG,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,QAAQ;EACnF,CAAC;CACH;CAEA,SAAS,IAAgB;EACnB,MAEJ,IAAa,IACb,EAAmB,MAAM,GACzB,EAAQ,UAAU,GAClB,EAAe,IAAI,EAAwB,CAAC,GAC5C,EAAW;CACb;CAEA,SAAS,EAAM,IAA6B,CAAC,GAAkB;EAC7D,IAAI,GAAY,OAAO,QAAQ,QAAQ;EACvC,IAAI;GACF,EAAgB,EAAa,SAAS,eAAe;EACvD,SAAS,GAAO;GACd,OAAO,QAAQ,OAAO,CAAK;EAC7B;EAcA,OAZI,MAEJ,EAAQ,aAAa,GACrB,EAAe,IAAI,EAAwB,oBAAoB,CAAC,GAChE,IAAe,EAAY,CAAY,CAAC,CAAC,WACjC,EAAQ,IACb,MAAmB;GAElB,MADA,EAAQ,GACF;EACR,CACF,GAEO;CACT;CAEA,SAAS,EAAY,GAAqB;EACxC,KAAU;CACZ;CAEA,SAAS,IAAuB;EAC9B,KAAa;CACf;CAEA,SAAS,IAAoB;EAC3B,KAAU;CACZ;CAEA,SAAS,EAAM,GAA6B;EAC1C,OAAO;GAAE;GAAQ;GAAW;GAAQ,QAAQ,IAAS,EAAgB;EAAO;CAC9E;CAEA,SAAS,IAAuB;EAG9B,OAFI,IAAmB,eAEhB,MAAW,IAAI,SAAS;CACjC;CAEA,OAAO;EACL,gBAAgB,EAAmB;EACnC;EACA,IAAI,WAAW;GACb,OAAO;EACT;EACA;EACA,IAAI,eAAe;GACjB,OAAO;EACT;EACA,QAAQ,EAAQ;EAChB;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;AACF"}
|
package/dist/_pool.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("./errors.cjs"),t=require("./_pool-core.cjs"),n=require("./_queue.cjs");let r=require("@vielzeug/arsenal
|
|
1
|
+
const e=require("./errors.cjs"),t=require("./_pool-core.cjs"),n=require("./_queue.cjs");let r=require("@vielzeug/arsenal");function i(i,a){let o=[...i],s=new n.TaskQueue,c=!1,l=t.createPoolCore({isIdle:()=>o.length===i.length&&s.size===0,onDispose(){for(let e of i)e.terminate();for(;s.size>0;){let t=s.shift();if(!t)break;t.cleanupAbort?.(),t.reject(new e.FamiliarTerminatedError)}},onDrainStart(){}});function u(){for(;s.size>0;){let e=s.shift();if(!e)break;if(e.signal?.aborted){e.cleanupAbort?.(),e.reject((0,r.abortError)(e.signal)),l.releaseCapacity();continue}return e}l.settleIdle()}function d(){if(!(c||l.disposed)){for(c=!0;!l.disposed&&o.length>0&&s.size>0;){let i=u();if(!i)break;let s=i,c=o.pop(),f=s.timeout??a.defaultTimeout;l.trackActive(1),l.releaseCapacity();let p=()=>{s.aborted=!0,c.cancel((0,r.abortError)(s.signal))};s.cleanupAbort=()=>{s.signal?.removeEventListener(`abort`,p),s.cleanupAbort=void 0},s.signal?.addEventListener(`abort`,p,{once:!0}),c.run(s.input,s.transferables,f).then(e=>t(e),e=>n(e));function t(e){s.cleanupAbort?.(),o.push(c),l.trackActive(-1),l.trackCompleted(),s.resolve(e),d(),l.settleIdle()}function n(t){s.cleanupAbort?.(),o.push(c),l.trackActive(-1),!s.aborted&&!(t instanceof e.FamiliarTerminatedError)&&l.trackFailed(),s.reject(t),d(),l.settleIdle()}}c=!1}}async function f(n,i={}){let{signal:o}=i,c=t.validatePriority(i.priority??0),u=t.validateTimeout(i.timeout),f=[...i.transferables??[]];if(l.disposed)throw new e.FamiliarTerminatedError;if(l.drainPromise)throw new e.FamiliarTerminatedError(`Worker is draining`);if(o?.aborted)throw(0,r.abortError)(o);for(;a.onFull===`wait`&&a.maxQueue!==void 0&&s.size>=a.maxQueue;){if(await l.waitForCapacity(o,c),l.disposed)throw new e.FamiliarTerminatedError;if(l.drainPromise)throw new e.FamiliarTerminatedError(`Worker is draining`);if(o?.aborted)throw l.releaseCapacity(),(0,r.abortError)(o)}let p,m,h=new Promise((e,t)=>{p=e,m=t}),g={input:n,priority:c,reject:m,resolve:p,signal:o,timeout:u,transferables:f};if(!s.enqueue(g,a.onFull===`wait`?void 0:a.maxQueue))throw new e.FamiliarQueueFullError(a.maxQueue);if(o){let e=()=>{s.remove(g)&&(g.cleanupAbort?.(),m((0,r.abortError)(o)),l.releaseCapacity(),l.settleIdle())};g.cleanupAbort=()=>{o.removeEventListener(`abort`,e),g.cleanupAbort=void 0},o.addEventListener(`abort`,e,{once:!0})}return d(),h}return{get disposalSignal(){return l.disposalSignal},dispose:l.dispose,get disposed(){return l.disposed},drain:l.drain,run:f,get stats(){return l.stats(s.size)},get status(){return l.status()},[Symbol.asyncDispose]:()=>l.drain({}),[Symbol.dispose]:l.dispose}}function a(t,n,i={}){let a,o=async function*(e){let a=[],o=()=>e.abort(i.signal?.reason);i.signal?.aborted?e.abort(i.signal.reason):i.signal?.addEventListener(`abort`,o,{once:!0});try{for(let[r,o]of n.entries()){let n=t.run(o,{priority:i.priority,signal:e.signal,timeout:i.timeout,transferables:i.getTransferables?.(o,r)}).catch(t=>{throw e.abort(t),t});n.catch(()=>void 0),a.push(n)}if(a.length===0&&e.signal.aborted)throw(0,r.abortError)(e.signal);for(let t of a){if(e.signal.aborted)throw(0,r.abortError)(e.signal);let n=await t;if(e.signal.aborted)throw(0,r.abortError)(e.signal);yield n}}catch(t){throw e.abort(t),t}finally{i.signal?.removeEventListener(`abort`,o),e.abort(new DOMException(`Batch consumer stopped`,`AbortError`)),await Promise.allSettled(a)}};return{[Symbol.asyncIterator](){let t={},n=new AbortController,r,i=()=>{if(a??=t,a===t)return r??=o(n),r};return{next:()=>i()?.next()??Promise.reject(new e.FamiliarRuntimeError(`Worker batches can only be consumed once`)),return:async i=>!a||a!==t?{done:!0,value:i}:(n.abort(new e.FamiliarTerminatedError(`Batch consumer stopped`)),r?.return(i)??{done:!0,value:i}),throw:async t=>{let r=i();if(!r)throw new e.FamiliarRuntimeError(`Worker batches can only be consumed once`);return n.abort(t),r.throw(t)}}}}}exports.createPool=i,exports.runBatch=a;
|
|
2
2
|
//# sourceMappingURL=_pool.cjs.map
|
package/dist/_pool.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_pool.cjs","names":[],"sources":["../src/_pool.ts"],"sourcesContent":["import { abortError } from '@vielzeug/arsenal/async';\nimport { createPoolCore, type PoolCore, type PoolOptions } from './_pool-core';\nimport { type QueueItem, TaskQueue } from './_queue';\nimport { FamiliarQueueFullError, FamiliarTerminatedError } from './errors';\nimport type { RunOptions, SlotStrategy, TaskGroup, TaskGroupOptions, WorkerPool } from './types';\n\nexport type { PoolOptions } from './_pool-core';\n\nexport function createPool<TInput, TOutput>(\n slots: SlotStrategy<TInput, TOutput>[],\n options: PoolOptions,\n): WorkerPool<TInput, TOutput> {\n const freeSlots = [...slots];\n const queue = new TaskQueue<TInput, TOutput>();\n let draining = false;\n\n const isIdle = (): boolean => freeSlots.length === slots.length && queue.size === 0;\n\n const core: PoolCore = createPoolCore({\n isIdle,\n onDispose() {\n for (const slot of slots) slot.terminate();\n\n while (queue.size > 0) {\n const item = queue.shift();\n\n if (!item) break;\n\n item.cleanupAbort?.();\n item.reject(new FamiliarTerminatedError());\n }\n },\n onDrainStart() {\n // No pending waiters to reject for the queue-based pool; capacity waiters\n // are rejected by the core's drain().\n },\n });\n\n function nextItem(): QueueItem<TInput, TOutput> | undefined {\n while (queue.size > 0) {\n const item = queue.shift();\n\n if (!item) break;\n\n if (item.signal?.aborted) {\n item.cleanupAbort?.();\n item.reject(abortError(item.signal));\n core.releaseCapacity();\n continue;\n }\n\n return item;\n }\n\n core.settleIdle();\n\n return undefined;\n }\n\n function drainQueue(): void {\n if (draining || core.disposed) return;\n\n draining = true;\n\n while (!core.disposed && freeSlots.length > 0 && queue.size > 0) {\n const next = nextItem();\n\n if (!next) break;\n\n const item = next;\n const slot = freeSlots.pop()!;\n const timeout = item.timeout ?? options.defaultTimeout;\n\n core.trackActive(1);\n core.releaseCapacity();\n\n const onAbort = () => slot.cancel(abortError(item.signal!));\n\n item.cleanupAbort = () => {\n item.signal?.removeEventListener('abort', onAbort);\n item.cleanupAbort = undefined;\n };\n item.signal?.addEventListener('abort', onAbort, { once: true });\n\n slot.run(item.input, item.transferables, timeout).then(\n (value) => finish(value),\n (error: unknown) => fail(error),\n );\n\n function finish(value: TOutput): void {\n item.cleanupAbort?.();\n freeSlots.push(slot);\n core.trackActive(-1);\n core.trackCompleted();\n item.resolve(value);\n drainQueue();\n core.settleIdle();\n }\n\n function fail(error: unknown): void {\n item.cleanupAbort?.();\n freeSlots.push(slot);\n core.trackActive(-1);\n\n if (!(error instanceof FamiliarTerminatedError) && error instanceof Error && error.name !== 'AbortError')\n core.trackFailed();\n\n item.reject(error);\n drainQueue();\n core.settleIdle();\n }\n }\n\n draining = false;\n }\n\n async function run(input: TInput, runOptions: RunOptions = {}): Promise<TOutput> {\n const { priority = 0, signal, timeout, transferables = [] } = runOptions;\n\n if (core.disposed) throw new FamiliarTerminatedError();\n\n if (core.drainPromise) throw new FamiliarTerminatedError('Worker is draining');\n\n if (signal?.aborted) throw abortError(signal);\n\n while (options.onFull === 'wait' && options.maxQueue !== undefined && queue.size >= options.maxQueue) {\n await core.waitForCapacity(signal);\n\n if (core.disposed) throw new FamiliarTerminatedError();\n\n if (core.drainPromise) throw new FamiliarTerminatedError('Worker is draining');\n\n if (signal?.aborted) throw abortError(signal);\n }\n\n let resolve!: (value: TOutput) => void;\n let reject!: (reason: unknown) => void;\n const promise = new Promise<TOutput>((res, rej) => {\n resolve = res;\n reject = rej;\n });\n const item: QueueItem<TInput, TOutput> = { input, priority, reject, resolve, signal, timeout, transferables };\n\n if (!queue.enqueue(item, options.onFull === 'wait' ? undefined : options.maxQueue)) {\n throw new FamiliarQueueFullError(options.maxQueue!);\n }\n\n if (signal) {\n const onAbort = () => {\n if (!queue.remove(item)) return;\n\n item.cleanupAbort?.();\n reject(abortError(signal));\n core.releaseCapacity();\n core.settleIdle();\n };\n\n item.cleanupAbort = () => {\n signal.removeEventListener('abort', onAbort);\n item.cleanupAbort = undefined;\n };\n signal.addEventListener('abort', onAbort, { once: true });\n }\n\n drainQueue();\n\n return promise;\n }\n\n return {\n get disposalSignal() {\n return core.disposalSignal;\n },\n dispose: core.dispose,\n get disposed() {\n return core.disposed;\n },\n drain: core.drain,\n async prime(): Promise<void> {\n await core.prime(slots);\n },\n run,\n get stats() {\n return core.stats(queue.size);\n },\n get status() {\n return core.status();\n },\n [Symbol.asyncDispose]: () => core.drain({}),\n [Symbol.dispose]: core.dispose,\n };\n}\n\nexport async function* batch<TInput, TOutput>(\n pool: WorkerPool<TInput, TOutput>,\n inputs: readonly TInput[],\n options: RunOptions = {},\n): AsyncIterable<TOutput> {\n const controller = new AbortController();\n const onAbort = () => controller.abort(options.signal?.reason);\n\n options.signal?.addEventListener('abort', onAbort, { once: true });\n\n const tasks = inputs.map((input) => pool.run(input, { ...options, signal: controller.signal }));\n\n try {\n for (const task of tasks) yield await task;\n } catch (error) {\n controller.abort(error);\n await Promise.allSettled(tasks);\n throw error;\n } finally {\n options.signal?.removeEventListener('abort', onAbort);\n controller.abort();\n await Promise.allSettled(tasks);\n }\n}\n\nexport function createTaskGroup<TInput, TOutput>(\n pool: WorkerPool<TInput, TOutput>,\n name: string | undefined = undefined,\n options: TaskGroupOptions = {},\n): TaskGroup<TInput, TOutput> {\n const controller = new AbortController();\n const tasks = new Set<Promise<TOutput>>();\n let size = 0;\n const onAbort = () => controller.abort(options.signal?.reason);\n\n options.signal?.addEventListener('abort', onAbort, { once: true });\n\n return {\n abort(reason?: unknown): void {\n controller.abort(reason);\n },\n async drain(): Promise<PromiseSettledResult<TOutput>[]> {\n return Promise.allSettled([...tasks]);\n },\n get name() {\n return name;\n },\n get pending() {\n return tasks.size;\n },\n run(input, runOptions = {}): Promise<TOutput> {\n const task = pool.run(input, { ...runOptions, signal: controller.signal });\n\n size += 1;\n tasks.add(task);\n void task.finally(() => tasks.delete(task));\n\n return task;\n },\n get size() {\n return size;\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"_pool.cjs","names":[],"sources":["../src/_pool.ts"],"sourcesContent":["import { abortError } from '@vielzeug/arsenal';\nimport { createPoolCore, type PoolCore, type PoolOptions, validatePriority, validateTimeout } from './_pool-core.js';\nimport { type QueueItem, TaskQueue } from './_queue.js';\nimport { FamiliarQueueFullError, FamiliarRuntimeError, FamiliarTerminatedError } from './errors.js';\nimport type { RunOptions, SlotStrategy, WorkerPool } from './types.js';\n\nexport type { PoolOptions } from './_pool-core.js';\n\nexport function createPool<TInput, TOutput>(\n slots: SlotStrategy<TInput, TOutput>[],\n options: PoolOptions,\n): WorkerPool<TInput, TOutput> {\n const freeSlots = [...slots];\n const queue = new TaskQueue<TInput, TOutput>();\n let draining = false;\n\n const isIdle = (): boolean => freeSlots.length === slots.length && queue.size === 0;\n\n const core: PoolCore = createPoolCore({\n isIdle,\n onDispose() {\n for (const slot of slots) slot.terminate();\n\n while (queue.size > 0) {\n const item = queue.shift();\n\n if (!item) break;\n\n item.cleanupAbort?.();\n item.reject(new FamiliarTerminatedError());\n }\n },\n onDrainStart() {\n // No pending waiters to reject for the queue-based pool; capacity waiters\n // are rejected by the core's drain().\n },\n });\n\n function nextItem(): QueueItem<TInput, TOutput> | undefined {\n while (queue.size > 0) {\n const item = queue.shift();\n\n if (!item) break;\n\n if (item.signal?.aborted) {\n item.cleanupAbort?.();\n item.reject(abortError(item.signal));\n core.releaseCapacity();\n continue;\n }\n\n return item;\n }\n\n core.settleIdle();\n\n return undefined;\n }\n\n function drainQueue(): void {\n if (draining || core.disposed) return;\n\n draining = true;\n\n while (!core.disposed && freeSlots.length > 0 && queue.size > 0) {\n const next = nextItem();\n\n if (!next) break;\n\n const item = next;\n const slot = freeSlots.pop()!;\n const timeout = item.timeout ?? options.defaultTimeout;\n\n core.trackActive(1);\n core.releaseCapacity();\n\n const onAbort = () => {\n item.aborted = true;\n slot.cancel(abortError(item.signal!));\n };\n\n item.cleanupAbort = () => {\n item.signal?.removeEventListener('abort', onAbort);\n item.cleanupAbort = undefined;\n };\n item.signal?.addEventListener('abort', onAbort, { once: true });\n\n slot.run(item.input, item.transferables, timeout).then(\n (value) => finish(value),\n (error: unknown) => fail(error),\n );\n\n function finish(value: TOutput): void {\n item.cleanupAbort?.();\n freeSlots.push(slot);\n core.trackActive(-1);\n core.trackCompleted();\n item.resolve(value);\n drainQueue();\n core.settleIdle();\n }\n\n function fail(error: unknown): void {\n item.cleanupAbort?.();\n freeSlots.push(slot);\n core.trackActive(-1);\n\n if (!item.aborted && !(error instanceof FamiliarTerminatedError)) core.trackFailed();\n\n item.reject(error);\n drainQueue();\n core.settleIdle();\n }\n }\n\n draining = false;\n }\n\n async function run(input: TInput, runOptions: RunOptions = {}): Promise<TOutput> {\n const { signal } = runOptions;\n const priority = validatePriority(runOptions.priority ?? 0);\n const timeout = validateTimeout(runOptions.timeout);\n const transferables = [...(runOptions.transferables ?? [])];\n\n if (core.disposed) throw new FamiliarTerminatedError();\n\n if (core.drainPromise) throw new FamiliarTerminatedError('Worker is draining');\n\n if (signal?.aborted) throw abortError(signal);\n\n while (options.onFull === 'wait' && options.maxQueue !== undefined && queue.size >= options.maxQueue) {\n await core.waitForCapacity(signal, priority);\n\n if (core.disposed) throw new FamiliarTerminatedError();\n\n if (core.drainPromise) throw new FamiliarTerminatedError('Worker is draining');\n\n if (signal?.aborted) {\n core.releaseCapacity();\n throw abortError(signal);\n }\n }\n\n let resolve!: (value: TOutput) => void;\n let reject!: (reason: unknown) => void;\n const promise = new Promise<TOutput>((res, rej) => {\n resolve = res;\n reject = rej;\n });\n const item: QueueItem<TInput, TOutput> = { input, priority, reject, resolve, signal, timeout, transferables };\n\n if (!queue.enqueue(item, options.onFull === 'wait' ? undefined : options.maxQueue)) {\n throw new FamiliarQueueFullError(options.maxQueue!);\n }\n\n if (signal) {\n const onAbort = () => {\n if (!queue.remove(item)) return;\n\n item.cleanupAbort?.();\n reject(abortError(signal));\n core.releaseCapacity();\n core.settleIdle();\n };\n\n item.cleanupAbort = () => {\n signal.removeEventListener('abort', onAbort);\n item.cleanupAbort = undefined;\n };\n signal.addEventListener('abort', onAbort, { once: true });\n }\n\n drainQueue();\n\n return promise;\n }\n\n return {\n get disposalSignal() {\n return core.disposalSignal;\n },\n dispose: core.dispose,\n get disposed() {\n return core.disposed;\n },\n drain: core.drain,\n run,\n get stats() {\n return core.stats(queue.size);\n },\n get status() {\n return core.status();\n },\n [Symbol.asyncDispose]: () => core.drain({}),\n [Symbol.dispose]: core.dispose,\n };\n}\n\nexport type BatchOptions<TInput> = Pick<RunOptions, 'priority' | 'signal' | 'timeout'> & {\n getTransferables?: (input: TInput, index: number) => readonly Transferable[];\n};\n\n/** Run related tasks concurrently and yield their results in input order. */\nexport function runBatch<TInput, TOutput>(\n pool: WorkerPool<TInput, TOutput>,\n inputs: readonly TInput[],\n options: BatchOptions<TInput> = {},\n): AsyncIterable<TOutput> {\n let owner: object | undefined;\n\n const iterate = async function* (controller: AbortController): AsyncGenerator<TOutput> {\n const tasks: Promise<TOutput>[] = [];\n const onAbort = () => controller.abort(options.signal?.reason);\n\n if (options.signal?.aborted) controller.abort(options.signal.reason);\n else options.signal?.addEventListener('abort', onAbort, { once: true });\n\n try {\n for (const [index, input] of inputs.entries()) {\n const task = pool\n .run(input, {\n priority: options.priority,\n signal: controller.signal,\n timeout: options.timeout,\n transferables: options.getTransferables?.(input, index),\n })\n .catch((error: unknown) => {\n controller.abort(error);\n throw error;\n });\n\n void task.catch(() => undefined);\n tasks.push(task);\n }\n\n if (tasks.length === 0 && controller.signal.aborted) throw abortError(controller.signal);\n for (const task of tasks) {\n if (controller.signal.aborted) throw abortError(controller.signal);\n const value = await task;\n if (controller.signal.aborted) throw abortError(controller.signal);\n yield value;\n }\n } catch (error) {\n controller.abort(error);\n throw error;\n } finally {\n options.signal?.removeEventListener('abort', onAbort);\n controller.abort(new DOMException('Batch consumer stopped', 'AbortError'));\n await Promise.allSettled(tasks);\n }\n };\n\n return {\n [Symbol.asyncIterator]() {\n const token = {};\n const controller = new AbortController();\n let iterator: AsyncGenerator<TOutput> | undefined;\n const start = (): AsyncGenerator<TOutput> | undefined => {\n owner ??= token;\n if (owner !== token) return undefined;\n iterator ??= iterate(controller);\n return iterator;\n };\n\n return {\n next: () =>\n start()?.next() ?? Promise.reject(new FamiliarRuntimeError('Worker batches can only be consumed once')),\n return: async (value?: unknown) => {\n if (!owner || owner !== token) return { done: true, value: value as TOutput };\n controller.abort(new FamiliarTerminatedError('Batch consumer stopped'));\n return iterator?.return(value as TOutput) ?? { done: true, value: value as TOutput };\n },\n throw: async (error?: unknown) => {\n const active = start();\n if (!active) throw new FamiliarRuntimeError('Worker batches can only be consumed once');\n controller.abort(error);\n return active.throw(error);\n },\n };\n },\n };\n}\n"],"mappings":"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"}
|
package/dist/_pool.d.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import { type PoolOptions } from './_pool-core';
|
|
2
|
-
import type { RunOptions, SlotStrategy,
|
|
3
|
-
export type { PoolOptions } from './_pool-core';
|
|
1
|
+
import { type PoolOptions } from './_pool-core.js';
|
|
2
|
+
import type { RunOptions, SlotStrategy, WorkerPool } from './types.js';
|
|
3
|
+
export type { PoolOptions } from './_pool-core.js';
|
|
4
4
|
export declare function createPool<TInput, TOutput>(slots: SlotStrategy<TInput, TOutput>[], options: PoolOptions): WorkerPool<TInput, TOutput>;
|
|
5
|
-
export
|
|
6
|
-
|
|
5
|
+
export type BatchOptions<TInput> = Pick<RunOptions, 'priority' | 'signal' | 'timeout'> & {
|
|
6
|
+
getTransferables?: (input: TInput, index: number) => readonly Transferable[];
|
|
7
|
+
};
|
|
8
|
+
/** Run related tasks concurrently and yield their results in input order. */
|
|
9
|
+
export declare function runBatch<TInput, TOutput>(pool: WorkerPool<TInput, TOutput>, inputs: readonly TInput[], options?: BatchOptions<TInput>): AsyncIterable<TOutput>;
|
|
7
10
|
//# sourceMappingURL=_pool.d.ts.map
|
package/dist/_pool.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_pool.d.ts","sourceRoot":"","sources":["../src/_pool.ts"],"names":[],"mappings":"AACA,OAAO,EAAiC,KAAK,WAAW,
|
|
1
|
+
{"version":3,"file":"_pool.d.ts","sourceRoot":"","sources":["../src/_pool.ts"],"names":[],"mappings":"AACA,OAAO,EAAiC,KAAK,WAAW,EAAqC,MAAM,iBAAiB,CAAC;AAGrH,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEvE,YAAY,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAEnD,wBAAgB,UAAU,CAAC,MAAM,EAAE,OAAO,EACxC,KAAK,EAAE,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EACtC,OAAO,EAAE,WAAW,GACnB,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,CAyL7B;AAED,MAAM,MAAM,YAAY,CAAC,MAAM,IAAI,IAAI,CAAC,UAAU,EAAE,UAAU,GAAG,QAAQ,GAAG,SAAS,CAAC,GAAG;IACvF,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,SAAS,YAAY,EAAE,CAAC;CAC9E,CAAC;AAEF,6EAA6E;AAC7E,wBAAgB,QAAQ,CAAC,MAAM,EAAE,OAAO,EACtC,IAAI,EAAE,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,MAAM,EAAE,SAAS,MAAM,EAAE,EACzB,OAAO,GAAE,YAAY,CAAC,MAAM,CAAM,GACjC,aAAa,CAAC,OAAO,CAAC,CA0ExB"}
|