@vielzeug/familiar 3.0.0 → 26.10.1

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.
Files changed (70) hide show
  1. package/README.md +1 -1
  2. package/dist/_pool-core.cjs +1 -1
  3. package/dist/_pool-core.cjs.map +1 -1
  4. package/dist/_pool-core.d.ts +38 -18
  5. package/dist/_pool-core.d.ts.map +1 -1
  6. package/dist/_pool-core.js +1 -117
  7. package/dist/_pool-core.js.map +1 -1
  8. package/dist/_pool.cjs +1 -1
  9. package/dist/_pool.cjs.map +1 -1
  10. package/dist/_pool.d.ts +1 -1
  11. package/dist/_pool.d.ts.map +1 -1
  12. package/dist/_pool.js +1 -158
  13. package/dist/_pool.js.map +1 -1
  14. package/dist/_stream-pool.cjs +1 -1
  15. package/dist/_stream-pool.cjs.map +1 -1
  16. package/dist/_stream-pool.d.ts +8 -3
  17. package/dist/_stream-pool.d.ts.map +1 -1
  18. package/dist/_stream-pool.js +1 -117
  19. package/dist/_stream-pool.js.map +1 -1
  20. package/dist/_timers.cjs +1 -1
  21. package/dist/_timers.cjs.map +1 -1
  22. package/dist/_timers.js +1 -7
  23. package/dist/_timers.js.map +1 -1
  24. package/dist/errors.cjs +1 -1
  25. package/dist/errors.cjs.map +1 -1
  26. package/dist/errors.d.ts +0 -7
  27. package/dist/errors.d.ts.map +1 -1
  28. package/dist/errors.js +1 -33
  29. package/dist/errors.js.map +1 -1
  30. package/dist/familiar.cjs +1 -1
  31. package/dist/familiar.cjs.map +1 -1
  32. package/dist/familiar.iife.js +1 -1
  33. package/dist/familiar.iife.js.map +1 -1
  34. package/dist/familiar.js +1 -1
  35. package/dist/familiar.js.map +1 -1
  36. package/dist/index.d.ts +4 -1
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +1 -4
  39. package/dist/protocol.cjs +1 -1
  40. package/dist/protocol.cjs.map +1 -1
  41. package/dist/protocol.js +1 -78
  42. package/dist/protocol.js.map +1 -1
  43. package/dist/testing/testing.cjs +1 -1
  44. package/dist/testing/testing.cjs.map +1 -1
  45. package/dist/testing/testing.d.ts +1 -1
  46. package/dist/testing/testing.d.ts.map +1 -1
  47. package/dist/testing/testing.js +1 -76
  48. package/dist/testing/testing.js.map +1 -1
  49. package/dist/testing.js +1 -3
  50. package/dist/types.d.ts +16 -2
  51. package/dist/types.d.ts.map +1 -1
  52. package/dist/worker.cjs +1 -1
  53. package/dist/worker.cjs.map +1 -1
  54. package/dist/worker.d.ts +0 -8
  55. package/dist/worker.d.ts.map +1 -1
  56. package/dist/worker.js +1 -189
  57. package/dist/worker.js.map +1 -1
  58. package/package.json +6 -6
  59. package/dist/_dev.cjs +0 -2
  60. package/dist/_dev.cjs.map +0 -1
  61. package/dist/_dev.d.ts +0 -2
  62. package/dist/_dev.d.ts.map +0 -1
  63. package/dist/_dev.js +0 -6
  64. package/dist/_dev.js.map +0 -1
  65. package/dist/_queue.cjs +0 -2
  66. package/dist/_queue.cjs.map +0 -1
  67. package/dist/_queue.d.ts +0 -19
  68. package/dist/_queue.d.ts.map +0 -1
  69. package/dist/_queue.js +0 -54
  70. package/dist/_queue.js.map +0 -1
package/README.md CHANGED
@@ -45,4 +45,4 @@ try {
45
45
 
46
46
  ## License
47
47
 
48
- MIT © [Helmuth Saatkamp](https://github.com/helmuthdu) — part of the [Vielzeug](https://github.com/helmuthdu/vielzeug) monorepo.
48
+ MIT © [Helmuth Saatkamp](https://github.com/helmuthdu): part of the [Vielzeug](https://github.com/helmuthdu/vielzeug) monorepo.
@@ -1,2 +1,2 @@
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;
1
+ const e=require("./_timers.cjs"),t=require("./errors.cjs");let n=require("@vielzeug/arsenal");var r=2147483647;function validatePriority(e){if(!Number.isFinite(e))throw new t.FamiliarInvalidOptionsError("`priority` must be a finite number");return e}function validateTimeout(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 createPoolCore(r,i){let a=[...r],o=[],s=[],c=[],l=(0,n.tapper)(),u=new AbortController,d=0,f=0,p=0,m=0,h=0,g,_=!1;function isIdle(){return a.length===r.length&&o.length===0}function settleIdle(){if(isIdle())for(let e of s.splice(0))e.timer&&clearTimeout(e.timer),e.resolve()}function waitForIdle(n){return isIdle()?Promise.resolve():new Promise((r,i)=>{let a={reject:i,resolve:r};n.timeout!==void 0&&(a.timer=setTimeout(()=>{let e=s.indexOf(a);e!==-1&&s.splice(e,1),i(new t.FamiliarTimeoutError(n.timeout,`Drain`))},n.timeout),e.unrefTimer(a.timer)),s.push(a)})}function releaseCapacity(){c.shift()?.resolve()}function rejectCapacity(e){for(let t of c.splice(0))t.reject(e)}function waitForCapacity(e,t){return e?.aborted?Promise.reject((0,n.abortError)(e)):new Promise((r,i)=>{let a=!1,o={cleanup(){e?.removeEventListener(`abort`,onAbort)},priority:t,reject(e){if(a)return;a=!0,o.cleanup();let t=c.indexOf(o);t!==-1&&c.splice(t,1),i(e)},resolve(){a||(a=!0,o.cleanup(),r())},sequence:p++},onAbort=()=>o.reject((0,n.abortError)(e));e?.addEventListener(`abort`,onAbort,{once:!0}),c.push(o),c.sort((e,t)=>t.priority-e.priority||e.sequence-t.sequence)})}function acquire(e,r){let{priority:a,signal:s}=e;return s?.aborted?Promise.reject((0,n.abortError)(s)):(async()=>{for(;;){if(_)throw new t.FamiliarTerminatedError;if(g)throw new t.FamiliarTerminatedError(`Worker is draining`);if(i.maxQueue===void 0||o.length<i.maxQueue)return admit(e,r??(e=>e));if(i.onFull===`reject`)throw new t.FamiliarQueueFullError(i.maxQueue);if(await waitForCapacity(s,a),s?.aborted)throw releaseCapacity(),(0,n.abortError)(s)}})()}function admit(e,t){let{priority:r,signal:i}=e,s=a.pop();if(s)try{return Promise.resolve(t(s))}catch(e){return release(s),settleIdle(),Promise.reject(e)}return new Promise((e,a)=>{let s={cleanup(){s.signal?.removeEventListener(`abort`,onAbort)},priority:r,reject(e){s.cleanup();let t=o.indexOf(s);t!==-1&&(o.splice(t,1),releaseCapacity()),a(e),settleIdle()},sequence:f++,signal:i,start(n){s.cleanup();try{e(t(n))}catch(e){release(n),settleIdle(),a(e)}}},onAbort=()=>s.reject((0,n.abortError)(s.signal));s.signal?.addEventListener(`abort`,onAbort,{once:!0}),o.push(s),o.sort((e,t)=>t.priority-e.priority||e.sequence-t.sequence)})}function release(e){let t=o.shift();t?(t.start(e),releaseCapacity()):a.push(e)}function dispose(){if(!_){_=!0,u.abort();for(let e of r)e.terminate();for(let e of o.splice(0))e.reject(new t.FamiliarTerminatedError);rejectCapacity(new t.FamiliarTerminatedError),settleIdle(),l.emit({type:`dispose`}),l.clear()}}function drain(e={}){if(_)return Promise.resolve();try{validateTimeout(e.timeout,`drain.timeout`)}catch(e){return Promise.reject(e)}return g||(rejectCapacity(new t.FamiliarTerminatedError(`Worker is draining`)),g=waitForIdle(e).then(()=>dispose(),e=>{throw dispose(),e}),g)}return{acquire,disposalSignal:u.signal,dispose,get disposed(){return _},drain,get drainPromise(){return g},emitTap(e){l.emit(e)},release,settleIdle,stats(){return{active:d,completed:m,failed:h,queued:o.length+c.length}},status(){return _?`terminated`:d===0?`idle`:`running`},tap(e,t){return _?()=>void 0:l.tap(e,t)},trackActive(e){d+=e},trackCompleted(){m+=1},trackFailed(){h+=1}}}exports.MAX_TIMEOUT=r,exports.createPoolCore=createPoolCore,exports.validatePriority=validatePriority,exports.validateTimeout=validateTimeout;
2
2
  //# sourceMappingURL=_pool-core.cjs.map
@@ -1 +1 @@
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":"8FAMA,IAAa,EAAc,WAE3B,SAAgB,EAAiB,EAA0B,CACzD,GAAI,CAAC,OAAO,SAAS,CAAQ,EAAG,MAAM,IAAI,EAAA,4BAA4B,oCAAoC,EAC1G,OAAO,CACT,CAEA,SAAgB,EAAgB,EAA6B,EAAO,UAA+B,CACjG,GAAI,IAAY,IAAA,KAAc,CAAC,OAAO,UAAU,CAAO,GAAK,EAAU,GAAK,EAAA,YACzE,MAAM,IAAI,EAAA,4BAA4B,KAAK,EAAK,uCAAuC,GAAa,EAEtG,OAAO,CACT,CAgDA,SAAgB,EAAe,EAIlB,CACX,IAAM,EAAqB,IAAI,gBACzB,EAA4B,CAAC,EAC7B,EAAoC,CAAC,EACvC,EAAS,EACT,EAAmB,EACnB,EAAY,EACZ,EAAS,EACT,EACA,EAAa,GAEjB,SAAS,GAAmB,CACrB,KAAQ,OAAO,EAEpB,IAAK,IAAM,KAAU,EAAY,OAAO,CAAC,EACnC,EAAO,OAAO,aAAa,EAAO,KAAK,EAE3C,EAAO,QAAQ,CAEnB,CAEA,SAAS,EAAY,EAA2C,CAG9D,OAFI,EAAQ,OAAO,EAAU,QAAQ,QAAQ,EAEtC,IAAI,SAAe,EAAS,IAAW,CAC5C,IAAM,EAAqB,CAAE,SAAQ,SAAQ,EAEzC,EAAa,UAAY,IAAA,KAC3B,EAAO,MAAQ,eAAiB,CAC9B,IAAM,EAAQ,EAAY,QAAQ,CAAM,EAEpC,IAAU,IAAI,EAAY,OAAO,EAAO,CAAC,EAE7C,EAAO,IAAI,EAAA,qBAAqB,EAAa,QAAU,OAAO,CAAC,CACjE,EAAG,EAAa,OAAO,EACvB,EAAA,WAAW,EAAO,KAAK,GAGzB,EAAY,KAAK,CAAM,CACzB,CAAC,CACH,CAEA,SAAS,GAAwB,CAC/B,EAAgB,MAAM,CAAC,EAAE,QAAQ,CACnC,CAEA,SAAS,EAAe,EAAuB,CAC7C,IAAK,IAAM,KAAU,EAAgB,OAAO,CAAC,EAAG,EAAO,OAAO,CAAM,CACtE,CAEA,SAAS,EAAgB,EAAiC,EAAiC,CAGzF,OAFI,GAAQ,QAAgB,QAAQ,QAAA,EAAO,EAAA,WAAA,CAAW,CAAM,CAAC,EAEtD,IAAI,SAAe,EAAS,IAAW,CAC5C,IAAI,EAAU,GACR,EAAyB,CAC7B,SAAU,CACR,GAAQ,oBAAoB,QAAS,CAAO,CAC9C,EACA,WACA,OAAO,EAAQ,CACb,GAAI,EAAS,OAEb,EAAU,GACV,EAAO,QAAQ,EAEf,IAAM,EAAQ,EAAgB,QAAQ,CAAM,EAExC,IAAU,IAAI,EAAgB,OAAO,EAAO,CAAC,EAEjD,EAAO,CAAM,CACf,EACA,SAAU,CACJ,IAEJ,EAAU,GACV,EAAO,QAAQ,EACf,EAAQ,EACV,EACA,SAAU,GACZ,EACM,MAAgB,EAAO,QAAA,EAAO,EAAA,WAAA,CAAW,CAAO,CAAC,EAEvD,GAAQ,iBAAiB,QAAS,EAAS,CAAE,KAAM,EAAK,CAAC,EACzD,EAAgB,KAAK,CAAM,EAC3B,EAAgB,MAAM,EAAG,IAAM,EAAE,SAAW,EAAE,UAAY,EAAE,SAAW,EAAE,QAAQ,CACnF,CAAC,CACH,CAEA,SAAS,GAAgB,CACnB,IAEJ,EAAa,GACb,EAAmB,MAAM,EACzB,EAAQ,UAAU,EAClB,EAAe,IAAI,EAAA,uBAAyB,EAC5C,EAAW,EACb,CAEA,SAAS,EAAM,EAA6B,CAAC,EAAkB,CAC7D,GAAI,EAAY,OAAO,QAAQ,QAAQ,EACvC,GAAI,CACF,EAAgB,EAAa,QAAS,eAAe,CACvD,OAAS,EAAO,CACd,OAAO,QAAQ,OAAO,CAAK,CAC7B,CAcA,OAZI,IAEJ,EAAQ,aAAa,EACrB,EAAe,IAAI,EAAA,wBAAwB,oBAAoB,CAAC,EAChE,EAAe,EAAY,CAAY,CAAC,CAAC,SACjC,EAAQ,EACb,GAAmB,CAElB,MADA,EAAQ,EACF,CACR,CACF,EAEO,EACT,CAEA,SAAS,EAAY,EAAqB,CACxC,GAAU,CACZ,CAEA,SAAS,GAAuB,CAC9B,GAAa,CACf,CAEA,SAAS,GAAoB,CAC3B,GAAU,CACZ,CAEA,SAAS,EAAM,EAA6B,CAC1C,MAAO,CAAE,SAAQ,YAAW,SAAQ,OAAQ,EAAS,EAAgB,MAAO,CAC9E,CAEA,SAAS,GAAuB,CAG9B,OAFI,EAAmB,aAEhB,IAAW,EAAI,OAAS,SACjC,CAEA,MAAO,CACL,eAAgB,EAAmB,OACnC,UACA,IAAI,UAAW,CACb,OAAO,CACT,EACA,QACA,IAAI,cAAe,CACjB,OAAO,CACT,EACA,OAAQ,EAAQ,OAChB,iBACA,kBACA,aACA,QACA,SACA,cACA,iBACA,cACA,kBACA,aACF,CACF"}
1
+ {"version":3,"file":"_pool-core.cjs","names":[],"sources":["../src/_pool-core.ts"],"sourcesContent":["import { abortError, tapper } from '@vielzeug/arsenal';\nimport { unrefTimer } from './_timers.js';\nimport {\n FamiliarInvalidOptionsError,\n FamiliarQueueFullError,\n type FamiliarRuntimeError,\n FamiliarTerminatedError,\n FamiliarTimeoutError,\n} from './errors.js';\nimport type { DrainOptions, FamiliarTapEvent, 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 defaultTimeout: number | undefined;\n maxQueue: number | undefined;\n onFull: 'reject' | 'wait';\n};\n\nexport type AcquireOptions = {\n priority: number;\n signal?: AbortSignal;\n};\n\n/**\n * A pool slot: tearable on disposal, with an optional channel for reporting\n * unhandled runtime errors. Pool factories wire `notify` to the core's tap so\n * slot owners can emit without holding a pool reference.\n */\nexport type PoolSlot = {\n notify?(error: FamiliarRuntimeError): void;\n terminate(): void;\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\ntype SlotWaiter<TSlot> = {\n cleanup(): void;\n priority: number;\n reject(reason: unknown): void;\n start(slot: TSlot): void;\n sequence: number;\n signal?: AbortSignal;\n};\n\nexport interface PoolCore<TSlot> {\n /**\n * Acquire a free slot and hand it to `fn`, which runs the acquired work.\n * `fn` is invoked synchronously both for an immediately free slot and when\n * a release hands the next waiter its slot, so dispatch never lags a\n * release by a microtask. Honors priority, FIFO order, abort, and `maxQueue`\n * admission; failures surface as a rejected promise. Without `fn`, resolves\n * with the slot instead.\n */\n acquire(options: AcquireOptions): Promise<TSlot>;\n acquire<R>(options: AcquireOptions, fn: (slot: TSlot) => R | Promise<R>): Promise<R>;\n readonly disposalSignal: AbortSignal;\n dispose(): void;\n readonly disposed: boolean;\n drain(options?: DrainOptions): Promise<void>;\n readonly drainPromise: Promise<void> | undefined;\n emitTap(event: FamiliarTapEvent): void;\n /** Return a slot to the pool, handing it to the highest-priority waiter if any. */\n release(slot: TSlot): void;\n settleIdle(): void;\n stats(): WorkerStats;\n status(): WorkerStatus;\n tap(handler: (event: FamiliarTapEvent) => void, options?: { readonly signal?: AbortSignal }): () => void;\n trackActive(delta: number): void;\n trackCompleted(): void;\n trackFailed(): void;\n}\n\n/**\n * The single slot scheduler shared by the result pool and the stream pool:\n * free-slot fast path, priority/FIFO waiter queue, `maxQueue` admission with\n * capacity waiters, idle/drain tracking, stats, disposal, and tap observation.\n * The two pools differ only in what they do with an acquired slot.\n */\nexport function createPoolCore<TSlot extends PoolSlot>(slots: readonly TSlot[], options: PoolOptions): PoolCore<TSlot> {\n const freeSlots = [...slots];\n const waiters: SlotWaiter<TSlot>[] = [];\n const idleWaiters: IdleWaiter[] = [];\n const capacityWaiters: CapacityWaiter[] = [];\n const tappers = tapper<FamiliarTapEvent>();\n const disposalController = new AbortController();\n let active = 0;\n let waiterSequence = 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 isIdle(): boolean {\n return freeSlots.length === slots.length && waiters.length === 0;\n }\n\n function settleIdle(): void {\n if (!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 (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 acquire<R>(acquireOptions: AcquireOptions, fn?: (slot: TSlot) => R | Promise<R>): Promise<R | TSlot> {\n const { priority, signal } = acquireOptions;\n\n if (signal?.aborted) return Promise.reject(abortError(signal));\n\n return (async () => {\n for (;;) {\n if (terminated) throw new FamiliarTerminatedError();\n\n if (drainPromise) throw new FamiliarTerminatedError('Worker is draining');\n\n if (options.maxQueue === undefined || waiters.length < options.maxQueue) {\n return admit(acquireOptions, (fn ?? ((slot) => slot)) as (slot: TSlot) => R | Promise<R>);\n }\n\n if (options.onFull === 'reject') throw new FamiliarQueueFullError(options.maxQueue);\n\n await waitForCapacity(signal, priority);\n\n if (signal?.aborted) {\n releaseCapacity();\n throw abortError(signal);\n }\n }\n })();\n }\n\n function admit<R>(acquireOptions: AcquireOptions, fn: (slot: TSlot) => R | Promise<R>): Promise<R> {\n const { priority, signal } = acquireOptions;\n\n const free = freeSlots.pop();\n\n if (free) {\n try {\n return Promise.resolve(fn(free));\n } catch (error) {\n // A synchronous throw must not strand the slot: idle would never settle.\n release(free);\n settleIdle();\n\n return Promise.reject(error);\n }\n }\n\n return new Promise<R>((resolve, reject) => {\n const waiter: SlotWaiter<TSlot> = {\n cleanup() {\n waiter.signal?.removeEventListener('abort', onAbort);\n },\n priority,\n reject(reason) {\n waiter.cleanup();\n\n const index = waiters.indexOf(waiter);\n\n if (index !== -1) {\n waiters.splice(index, 1);\n releaseCapacity();\n }\n\n reject(reason);\n settleIdle();\n },\n sequence: waiterSequence++,\n signal,\n start(slot) {\n waiter.cleanup();\n\n try {\n resolve(fn(slot));\n } catch (error) {\n release(slot);\n settleIdle();\n reject(error);\n }\n },\n };\n const onAbort = () => waiter.reject(abortError(waiter.signal!));\n\n waiter.signal?.addEventListener('abort', onAbort, { once: true });\n waiters.push(waiter);\n waiters.sort((a, b) => b.priority - a.priority || a.sequence - b.sequence);\n });\n }\n\n function release(slot: TSlot): void {\n const next = waiters.shift();\n\n if (next) {\n next.start(slot);\n releaseCapacity();\n } else {\n freeSlots.push(slot);\n }\n }\n\n function dispose(): void {\n if (terminated) return;\n\n terminated = true;\n disposalController.abort();\n\n for (const slot of slots) slot.terminate();\n\n for (const waiter of waiters.splice(0)) waiter.reject(new FamiliarTerminatedError());\n\n rejectCapacity(new FamiliarTerminatedError());\n settleIdle();\n tappers.emit({ type: 'dispose' });\n tappers.clear();\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 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 return {\n acquire,\n disposalSignal: disposalController.signal,\n dispose,\n get disposed() {\n return terminated;\n },\n drain,\n get drainPromise() {\n return drainPromise;\n },\n emitTap(event) {\n tappers.emit(event);\n },\n release,\n settleIdle,\n stats() {\n return { active, completed, failed, queued: waiters.length + capacityWaiters.length };\n },\n status() {\n if (terminated) return 'terminated';\n\n return active === 0 ? 'idle' : 'running';\n },\n tap(handler, tapOptions) {\n if (terminated) return () => undefined;\n\n return tappers.tap(handler, tapOptions);\n },\n trackActive(delta: number) {\n active += delta;\n },\n trackCompleted() {\n completed += 1;\n },\n trackFailed() {\n failed += 1;\n },\n };\n}\n"],"mappings":"8FAYA,IAAa,EAAc,WAE3B,SAAgB,iBAAiB,EAA0B,CACzD,GAAI,CAAC,OAAO,SAAS,CAAQ,EAAG,MAAM,IAAI,EAAA,4BAA4B,oCAAoC,EAC1G,OAAO,CACT,CAEA,SAAgB,gBAAgB,EAA6B,EAAO,UAA+B,CACjG,GAAI,IAAY,IAAA,KAAc,CAAC,OAAO,UAAU,CAAO,GAAK,EAAU,GAAK,EAAA,YACzE,MAAM,IAAI,EAAA,4BAA4B,KAAK,EAAK,uCAAuC,GAAa,EAEtG,OAAO,CACT,CAgFA,SAAgB,eAAuC,EAAyB,EAAuC,CACrH,IAAM,EAAY,CAAC,GAAG,CAAK,EACrB,EAA+B,CAAC,EAChC,EAA4B,CAAC,EAC7B,EAAoC,CAAC,EACrC,GAAA,EAAU,EAAA,OAAA,CAAyB,EACnC,EAAqB,IAAI,gBAC3B,EAAS,EACT,EAAiB,EACjB,EAAmB,EACnB,EAAY,EACZ,EAAS,EACT,EACA,EAAa,GAEjB,SAAS,QAAkB,CACzB,OAAO,EAAU,SAAW,EAAM,QAAU,EAAQ,SAAW,CACjE,CAEA,SAAS,YAAmB,CACrB,UAAO,EAEZ,IAAK,IAAM,KAAU,EAAY,OAAO,CAAC,EACnC,EAAO,OAAO,aAAa,EAAO,KAAK,EAE3C,EAAO,QAAQ,CAEnB,CAEA,SAAS,YAAY,EAA2C,CAG9D,OAFI,OAAO,EAAU,QAAQ,QAAQ,EAE9B,IAAI,SAAe,EAAS,IAAW,CAC5C,IAAM,EAAqB,CAAE,SAAQ,SAAQ,EAEzC,EAAa,UAAY,IAAA,KAC3B,EAAO,MAAQ,eAAiB,CAC9B,IAAM,EAAQ,EAAY,QAAQ,CAAM,EAEpC,IAAU,IAAI,EAAY,OAAO,EAAO,CAAC,EAE7C,EAAO,IAAI,EAAA,qBAAqB,EAAa,QAAU,OAAO,CAAC,CACjE,EAAG,EAAa,OAAO,EACvB,EAAA,WAAW,EAAO,KAAK,GAGzB,EAAY,KAAK,CAAM,CACzB,CAAC,CACH,CAEA,SAAS,iBAAwB,CAC/B,EAAgB,MAAM,CAAC,EAAE,QAAQ,CACnC,CAEA,SAAS,eAAe,EAAuB,CAC7C,IAAK,IAAM,KAAU,EAAgB,OAAO,CAAC,EAAG,EAAO,OAAO,CAAM,CACtE,CAEA,SAAS,gBAAgB,EAAiC,EAAiC,CAGzF,OAFI,GAAQ,QAAgB,QAAQ,QAAA,EAAO,EAAA,WAAA,CAAW,CAAM,CAAC,EAEtD,IAAI,SAAe,EAAS,IAAW,CAC5C,IAAI,EAAU,GACR,EAAyB,CAC7B,SAAU,CACR,GAAQ,oBAAoB,QAAS,OAAO,CAC9C,EACA,WACA,OAAO,EAAQ,CACb,GAAI,EAAS,OAEb,EAAU,GACV,EAAO,QAAQ,EAEf,IAAM,EAAQ,EAAgB,QAAQ,CAAM,EAExC,IAAU,IAAI,EAAgB,OAAO,EAAO,CAAC,EAEjD,EAAO,CAAM,CACf,EACA,SAAU,CACJ,IAEJ,EAAU,GACV,EAAO,QAAQ,EACf,EAAQ,EACV,EACA,SAAU,GACZ,EACM,YAAgB,EAAO,QAAA,EAAO,EAAA,WAAA,CAAW,CAAO,CAAC,EAEvD,GAAQ,iBAAiB,QAAS,QAAS,CAAE,KAAM,EAAK,CAAC,EACzD,EAAgB,KAAK,CAAM,EAC3B,EAAgB,MAAM,EAAG,IAAM,EAAE,SAAW,EAAE,UAAY,EAAE,SAAW,EAAE,QAAQ,CACnF,CAAC,CACH,CAEA,SAAS,QAAW,EAAgC,EAA0D,CAC5G,GAAM,CAAE,WAAU,UAAW,EAI7B,OAFI,GAAQ,QAAgB,QAAQ,QAAA,EAAO,EAAA,WAAA,CAAW,CAAM,CAAC,GAErD,SAAY,CAClB,OAAS,CACP,GAAI,EAAY,MAAM,IAAI,EAAA,wBAE1B,GAAI,EAAc,MAAM,IAAI,EAAA,wBAAwB,oBAAoB,EAExE,GAAI,EAAQ,WAAa,IAAA,IAAa,EAAQ,OAAS,EAAQ,SAC7D,OAAO,MAAM,EAAiB,IAAQ,GAAS,EAAyC,EAG1F,GAAI,EAAQ,SAAW,SAAU,MAAM,IAAI,EAAA,uBAAuB,EAAQ,QAAQ,EAIlF,GAFA,MAAM,gBAAgB,EAAQ,CAAQ,EAElC,GAAQ,QAEV,MADA,gBAAgB,GAChB,EAAM,EAAA,WAAA,CAAW,CAAM,CAE3B,CACF,EAAA,CAAG,CACL,CAEA,SAAS,MAAS,EAAgC,EAAiD,CACjG,GAAM,CAAE,WAAU,UAAW,EAEvB,EAAO,EAAU,IAAI,EAE3B,GAAI,EACF,GAAI,CACF,OAAO,QAAQ,QAAQ,EAAG,CAAI,CAAC,CACjC,OAAS,EAAO,CAKd,OAHA,QAAQ,CAAI,EACZ,WAAW,EAEJ,QAAQ,OAAO,CAAK,CAC7B,CAGF,OAAO,IAAI,SAAY,EAAS,IAAW,CACzC,IAAM,EAA4B,CAChC,SAAU,CACR,EAAO,QAAQ,oBAAoB,QAAS,OAAO,CACrD,EACA,WACA,OAAO,EAAQ,CACb,EAAO,QAAQ,EAEf,IAAM,EAAQ,EAAQ,QAAQ,CAAM,EAEhC,IAAU,KACZ,EAAQ,OAAO,EAAO,CAAC,EACvB,gBAAgB,GAGlB,EAAO,CAAM,EACb,WAAW,CACb,EACA,SAAU,IACV,SACA,MAAM,EAAM,CACV,EAAO,QAAQ,EAEf,GAAI,CACF,EAAQ,EAAG,CAAI,CAAC,CAClB,OAAS,EAAO,CACd,QAAQ,CAAI,EACZ,WAAW,EACX,EAAO,CAAK,CACd,CACF,CACF,EACM,YAAgB,EAAO,QAAA,EAAO,EAAA,WAAA,CAAW,EAAO,MAAO,CAAC,EAE9D,EAAO,QAAQ,iBAAiB,QAAS,QAAS,CAAE,KAAM,EAAK,CAAC,EAChE,EAAQ,KAAK,CAAM,EACnB,EAAQ,MAAM,EAAG,IAAM,EAAE,SAAW,EAAE,UAAY,EAAE,SAAW,EAAE,QAAQ,CAC3E,CAAC,CACH,CAEA,SAAS,QAAQ,EAAmB,CAClC,IAAM,EAAO,EAAQ,MAAM,EAEvB,GACF,EAAK,MAAM,CAAI,EACf,gBAAgB,GAEhB,EAAU,KAAK,CAAI,CAEvB,CAEA,SAAS,SAAgB,CACnB,MAGJ,CADA,EAAa,GACb,EAAmB,MAAM,EAEzB,IAAK,IAAM,KAAQ,EAAO,EAAK,UAAU,EAEzC,IAAK,IAAM,KAAU,EAAQ,OAAO,CAAC,EAAG,EAAO,OAAO,IAAI,EAAA,uBAAyB,EAEnF,eAAe,IAAI,EAAA,uBAAyB,EAC5C,WAAW,EACX,EAAQ,KAAK,CAAE,KAAM,SAAU,CAAC,EAChC,EAAQ,MAAM,CATW,CAU3B,CAEA,SAAS,MAAM,EAA6B,CAAC,EAAkB,CAC7D,GAAI,EAAY,OAAO,QAAQ,QAAQ,EACvC,GAAI,CACF,gBAAgB,EAAa,QAAS,eAAe,CACvD,OAAS,EAAO,CACd,OAAO,QAAQ,OAAO,CAAK,CAC7B,CAaA,OAXI,IAEJ,eAAe,IAAI,EAAA,wBAAwB,oBAAoB,CAAC,EAChE,EAAe,YAAY,CAAY,CAAC,CAAC,SACjC,QAAQ,EACb,GAAmB,CAElB,MADA,QAAQ,EACF,CACR,CACF,EAEO,EACT,CAEA,MAAO,CACL,QACA,eAAgB,EAAmB,OACnC,QACA,IAAI,UAAW,CACb,OAAO,CACT,EACA,MACA,IAAI,cAAe,CACjB,OAAO,CACT,EACA,QAAQ,EAAO,CACb,EAAQ,KAAK,CAAK,CACpB,EACA,QACA,WACA,OAAQ,CACN,MAAO,CAAE,SAAQ,YAAW,SAAQ,OAAQ,EAAQ,OAAS,EAAgB,MAAO,CACtF,EACA,QAAS,CAGP,OAFI,EAAmB,aAEhB,IAAW,EAAI,OAAS,SACjC,EACA,IAAI,EAAS,EAAY,CAGvB,OAFI,MAAyB,IAAA,GAEtB,EAAQ,IAAI,EAAS,CAAU,CACxC,EACA,YAAY,EAAe,CACzB,GAAU,CACZ,EACA,gBAAiB,CACf,GAAa,CACf,EACA,aAAc,CACZ,GAAU,CACZ,CACF,CACF"}
@@ -1,41 +1,61 @@
1
- import type { DrainOptions, WorkerStats, WorkerStatus } from './types.js';
1
+ import { type FamiliarRuntimeError } from './errors.js';
2
+ import type { DrainOptions, FamiliarTapEvent, WorkerStats, WorkerStatus } from './types.js';
2
3
  export declare const MAX_CONCURRENCY = 512;
3
4
  export declare const MAX_TIMEOUT = 2147483647;
4
5
  export declare function validatePriority(priority: number): number;
5
6
  export declare function validateTimeout(timeout: number | undefined, name?: string): number | undefined;
6
7
  export type PoolOptions = {
7
- concurrency: number;
8
8
  defaultTimeout: number | undefined;
9
9
  maxQueue: number | undefined;
10
10
  onFull: 'reject' | 'wait';
11
11
  };
12
- export interface PoolCore {
12
+ export type AcquireOptions = {
13
+ priority: number;
14
+ signal?: AbortSignal;
15
+ };
16
+ /**
17
+ * A pool slot: tearable on disposal, with an optional channel for reporting
18
+ * unhandled runtime errors. Pool factories wire `notify` to the core's tap so
19
+ * slot owners can emit without holding a pool reference.
20
+ */
21
+ export type PoolSlot = {
22
+ notify?(error: FamiliarRuntimeError): void;
23
+ terminate(): void;
24
+ };
25
+ export interface PoolCore<TSlot> {
26
+ /**
27
+ * Acquire a free slot and hand it to `fn`, which runs the acquired work.
28
+ * `fn` is invoked synchronously both for an immediately free slot and when
29
+ * a release hands the next waiter its slot, so dispatch never lags a
30
+ * release by a microtask. Honors priority, FIFO order, abort, and `maxQueue`
31
+ * admission; failures surface as a rejected promise. Without `fn`, resolves
32
+ * with the slot instead.
33
+ */
34
+ acquire(options: AcquireOptions): Promise<TSlot>;
35
+ acquire<R>(options: AcquireOptions, fn: (slot: TSlot) => R | Promise<R>): Promise<R>;
13
36
  readonly disposalSignal: AbortSignal;
14
37
  dispose(): void;
15
38
  readonly disposed: boolean;
16
39
  drain(options?: DrainOptions): Promise<void>;
17
40
  readonly drainPromise: Promise<void> | undefined;
18
- isIdle(): boolean;
19
- rejectCapacity(reason: unknown): void;
20
- releaseCapacity(): void;
41
+ emitTap(event: FamiliarTapEvent): void;
42
+ /** Return a slot to the pool, handing it to the highest-priority waiter if any. */
43
+ release(slot: TSlot): void;
21
44
  settleIdle(): void;
22
- stats(queued: number): WorkerStats;
45
+ stats(): WorkerStats;
23
46
  status(): WorkerStatus;
47
+ tap(handler: (event: FamiliarTapEvent) => void, options?: {
48
+ readonly signal?: AbortSignal;
49
+ }): () => void;
24
50
  trackActive(delta: number): void;
25
51
  trackCompleted(): void;
26
52
  trackFailed(): void;
27
- waitForCapacity(signal: AbortSignal | undefined, priority: number): Promise<void>;
28
- waitForIdle(options: DrainOptions): Promise<void>;
29
53
  }
30
54
  /**
31
- * Shared disposal controller, idle/capacity waiters, drain, and stats tracking
32
- * used by both the single-result pool (`_pool.ts`) and the stream pool
33
- * (`_stream-pool.ts`). Each pool provides its own `isIdle` predicate and
34
- * `onDispose`/`onDrainStart` hooks to flush pool-specific pending work.
55
+ * The single slot scheduler shared by the result pool and the stream pool:
56
+ * free-slot fast path, priority/FIFO waiter queue, `maxQueue` admission with
57
+ * capacity waiters, idle/drain tracking, stats, disposal, and tap observation.
58
+ * The two pools differ only in what they do with an acquired slot.
35
59
  */
36
- export declare function createPoolCore(options: {
37
- isIdle: () => boolean;
38
- onDispose: () => void;
39
- onDrainStart: () => void;
40
- }): PoolCore;
60
+ export declare function createPoolCore<TSlot extends PoolSlot>(slots: readonly TSlot[], options: PoolOptions): PoolCore<TSlot>;
41
61
  //# sourceMappingURL=_pool-core.d.ts.map
@@ -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,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"}
1
+ {"version":3,"file":"_pool-core.d.ts","sourceRoot":"","sources":["../src/_pool-core.ts"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,oBAAoB,EAG1B,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE5F,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,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,MAAM,EAAE,QAAQ,GAAG,MAAM,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,QAAQ,GAAG;IACrB,MAAM,CAAC,CAAC,KAAK,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAC3C,SAAS,IAAI,IAAI,CAAC;CACnB,CAAC;AAyBF,MAAM,WAAW,QAAQ,CAAC,KAAK;IAC7B;;;;;;;OAOG;IACH,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IACjD,OAAO,CAAC,CAAC,EAAE,OAAO,EAAE,cAAc,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACrF,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,OAAO,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACvC,mFAAmF;IACnF,OAAO,CAAC,IAAI,EAAE,KAAK,GAAG,IAAI,CAAC;IAC3B,UAAU,IAAI,IAAI,CAAC;IACnB,KAAK,IAAI,WAAW,CAAC;IACrB,MAAM,IAAI,YAAY,CAAC;IACvB,GAAG,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,EAAE,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GAAG,MAAM,IAAI,CAAC;IACzG,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,cAAc,IAAI,IAAI,CAAC;IACvB,WAAW,IAAI,IAAI,CAAC;CACrB;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,KAAK,SAAS,QAAQ,EAAE,KAAK,EAAE,SAAS,KAAK,EAAE,EAAE,OAAO,EAAE,WAAW,GAAG,QAAQ,CAAC,KAAK,CAAC,CA8QrH"}
@@ -1,118 +1,2 @@
1
- import { unrefTimer as e } from "./_timers.js";
2
- import { FamiliarInvalidOptionsError as t, FamiliarTerminatedError as n, FamiliarTimeoutError as r } from "./errors.js";
3
- import { abortError as i } from "@vielzeug/arsenal";
4
- //#region src/_pool-core.ts
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();
18
- }
19
- function g(n) {
20
- return t.isIdle() ? Promise.resolve() : new Promise((t, i) => {
21
- let a = {
22
- reject: i,
23
- resolve: t
24
- };
25
- n.timeout !== void 0 && (a.timer = setTimeout(() => {
26
- let e = o.indexOf(a);
27
- e !== -1 && o.splice(e, 1), i(new r(n.timeout, "Drain"));
28
- }, n.timeout), e(a.timer)), o.push(a);
29
- });
30
- }
31
- function _() {
32
- c.shift()?.resolve();
33
- }
34
- function v(e) {
35
- for (let t of c.splice(0)) t.reject(e);
36
- }
37
- function y(e, t) {
38
- return e?.aborted ? Promise.reject(i(e)) : new Promise((n, r) => {
39
- let a = !1, o = {
40
- cleanup() {
41
- e?.removeEventListener("abort", s);
42
- },
43
- priority: t,
44
- reject(e) {
45
- if (a) return;
46
- a = !0, o.cleanup();
47
- let t = c.indexOf(o);
48
- t !== -1 && c.splice(t, 1), r(e);
49
- },
50
- resolve() {
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);
56
- });
57
- }
58
- function b() {
59
- m || (m = !0, a.abort(), t.onDispose(), v(new n()), h());
60
- }
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);
71
- }
72
- function S(e) {
73
- l += e;
74
- }
75
- function C() {
76
- d += 1;
77
- }
78
- function w() {
79
- f += 1;
80
- }
81
- function T(e) {
82
- return {
83
- active: l,
84
- completed: d,
85
- failed: f,
86
- queued: e + c.length
87
- };
88
- }
89
- function E() {
90
- return m ? "terminated" : l === 0 ? "idle" : "running";
91
- }
92
- return {
93
- disposalSignal: a.signal,
94
- dispose: b,
95
- get disposed() {
96
- return m;
97
- },
98
- drain: x,
99
- get drainPromise() {
100
- return p;
101
- },
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
113
- };
114
- }
115
- //#endregion
116
- export { a as MAX_TIMEOUT, c as createPoolCore, o as validatePriority, s as validateTimeout };
117
-
1
+ import{unrefTimer as e}from"./_timers.js";import{FamiliarInvalidOptionsError as t,FamiliarQueueFullError as n,FamiliarTerminatedError as r,FamiliarTimeoutError as i}from"./errors.js";import{abortError as a,tapper as o}from"@vielzeug/arsenal";var s=2147483647;function validatePriority(e){if(!Number.isFinite(e))throw new t("`priority` must be a finite number");return e}function validateTimeout(e,n=`timeout`){if(e!==void 0&&(!Number.isInteger(e)||e<1||e>2147483647))throw new t(`\`${n}\` must be an integer from 1 through ${s}`);return e}function createPoolCore(t,s){let c=[...t],l=[],u=[],d=[],f=o(),p=new AbortController,m=0,h=0,g=0,_=0,v=0,y,b=!1;function isIdle(){return c.length===t.length&&l.length===0}function settleIdle(){if(isIdle())for(let e of u.splice(0))e.timer&&clearTimeout(e.timer),e.resolve()}function waitForIdle(t){return isIdle()?Promise.resolve():new Promise((n,r)=>{let a={reject:r,resolve:n};t.timeout!==void 0&&(a.timer=setTimeout(()=>{let e=u.indexOf(a);e!==-1&&u.splice(e,1),r(new i(t.timeout,`Drain`))},t.timeout),e(a.timer)),u.push(a)})}function releaseCapacity(){d.shift()?.resolve()}function rejectCapacity(e){for(let t of d.splice(0))t.reject(e)}function waitForCapacity(e,t){return e?.aborted?Promise.reject(a(e)):new Promise((n,r)=>{let i=!1,o={cleanup(){e?.removeEventListener(`abort`,onAbort)},priority:t,reject(e){if(i)return;i=!0,o.cleanup();let t=d.indexOf(o);t!==-1&&d.splice(t,1),r(e)},resolve(){i||(i=!0,o.cleanup(),n())},sequence:g++},onAbort=()=>o.reject(a(e));e?.addEventListener(`abort`,onAbort,{once:!0}),d.push(o),d.sort((e,t)=>t.priority-e.priority||e.sequence-t.sequence)})}function acquire(e,t){let{priority:i,signal:o}=e;return o?.aborted?Promise.reject(a(o)):(async()=>{for(;;){if(b)throw new r;if(y)throw new r(`Worker is draining`);if(s.maxQueue===void 0||l.length<s.maxQueue)return admit(e,t??(e=>e));if(s.onFull===`reject`)throw new n(s.maxQueue);if(await waitForCapacity(o,i),o?.aborted)throw releaseCapacity(),a(o)}})()}function admit(e,t){let{priority:n,signal:r}=e,i=c.pop();if(i)try{return Promise.resolve(t(i))}catch(e){return release(i),settleIdle(),Promise.reject(e)}return new Promise((e,i)=>{let o={cleanup(){o.signal?.removeEventListener(`abort`,onAbort)},priority:n,reject(e){o.cleanup();let t=l.indexOf(o);t!==-1&&(l.splice(t,1),releaseCapacity()),i(e),settleIdle()},sequence:h++,signal:r,start(n){o.cleanup();try{e(t(n))}catch(e){release(n),settleIdle(),i(e)}}},onAbort=()=>o.reject(a(o.signal));o.signal?.addEventListener(`abort`,onAbort,{once:!0}),l.push(o),l.sort((e,t)=>t.priority-e.priority||e.sequence-t.sequence)})}function release(e){let t=l.shift();t?(t.start(e),releaseCapacity()):c.push(e)}function dispose(){if(!b){b=!0,p.abort();for(let e of t)e.terminate();for(let e of l.splice(0))e.reject(new r);rejectCapacity(new r),settleIdle(),f.emit({type:`dispose`}),f.clear()}}function drain(e={}){if(b)return Promise.resolve();try{validateTimeout(e.timeout,`drain.timeout`)}catch(e){return Promise.reject(e)}return y||(rejectCapacity(new r(`Worker is draining`)),y=waitForIdle(e).then(()=>dispose(),e=>{throw dispose(),e}),y)}return{acquire,disposalSignal:p.signal,dispose,get disposed(){return b},drain,get drainPromise(){return y},emitTap(e){f.emit(e)},release,settleIdle,stats(){return{active:m,completed:_,failed:v,queued:l.length+d.length}},status(){return b?`terminated`:m===0?`idle`:`running`},tap(e,t){return b?()=>void 0:f.tap(e,t)},trackActive(e){m+=e},trackCompleted(){_+=1},trackFailed(){v+=1}}}export{s as MAX_TIMEOUT,createPoolCore,validatePriority,validateTimeout};
118
2
  //# sourceMappingURL=_pool-core.js.map
@@ -1 +1 @@
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":"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"}
1
+ {"version":3,"file":"_pool-core.js","names":[],"sources":["../src/_pool-core.ts"],"sourcesContent":["import { abortError, tapper } from '@vielzeug/arsenal';\nimport { unrefTimer } from './_timers.js';\nimport {\n FamiliarInvalidOptionsError,\n FamiliarQueueFullError,\n type FamiliarRuntimeError,\n FamiliarTerminatedError,\n FamiliarTimeoutError,\n} from './errors.js';\nimport type { DrainOptions, FamiliarTapEvent, 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 defaultTimeout: number | undefined;\n maxQueue: number | undefined;\n onFull: 'reject' | 'wait';\n};\n\nexport type AcquireOptions = {\n priority: number;\n signal?: AbortSignal;\n};\n\n/**\n * A pool slot: tearable on disposal, with an optional channel for reporting\n * unhandled runtime errors. Pool factories wire `notify` to the core's tap so\n * slot owners can emit without holding a pool reference.\n */\nexport type PoolSlot = {\n notify?(error: FamiliarRuntimeError): void;\n terminate(): void;\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\ntype SlotWaiter<TSlot> = {\n cleanup(): void;\n priority: number;\n reject(reason: unknown): void;\n start(slot: TSlot): void;\n sequence: number;\n signal?: AbortSignal;\n};\n\nexport interface PoolCore<TSlot> {\n /**\n * Acquire a free slot and hand it to `fn`, which runs the acquired work.\n * `fn` is invoked synchronously both for an immediately free slot and when\n * a release hands the next waiter its slot, so dispatch never lags a\n * release by a microtask. Honors priority, FIFO order, abort, and `maxQueue`\n * admission; failures surface as a rejected promise. Without `fn`, resolves\n * with the slot instead.\n */\n acquire(options: AcquireOptions): Promise<TSlot>;\n acquire<R>(options: AcquireOptions, fn: (slot: TSlot) => R | Promise<R>): Promise<R>;\n readonly disposalSignal: AbortSignal;\n dispose(): void;\n readonly disposed: boolean;\n drain(options?: DrainOptions): Promise<void>;\n readonly drainPromise: Promise<void> | undefined;\n emitTap(event: FamiliarTapEvent): void;\n /** Return a slot to the pool, handing it to the highest-priority waiter if any. */\n release(slot: TSlot): void;\n settleIdle(): void;\n stats(): WorkerStats;\n status(): WorkerStatus;\n tap(handler: (event: FamiliarTapEvent) => void, options?: { readonly signal?: AbortSignal }): () => void;\n trackActive(delta: number): void;\n trackCompleted(): void;\n trackFailed(): void;\n}\n\n/**\n * The single slot scheduler shared by the result pool and the stream pool:\n * free-slot fast path, priority/FIFO waiter queue, `maxQueue` admission with\n * capacity waiters, idle/drain tracking, stats, disposal, and tap observation.\n * The two pools differ only in what they do with an acquired slot.\n */\nexport function createPoolCore<TSlot extends PoolSlot>(slots: readonly TSlot[], options: PoolOptions): PoolCore<TSlot> {\n const freeSlots = [...slots];\n const waiters: SlotWaiter<TSlot>[] = [];\n const idleWaiters: IdleWaiter[] = [];\n const capacityWaiters: CapacityWaiter[] = [];\n const tappers = tapper<FamiliarTapEvent>();\n const disposalController = new AbortController();\n let active = 0;\n let waiterSequence = 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 isIdle(): boolean {\n return freeSlots.length === slots.length && waiters.length === 0;\n }\n\n function settleIdle(): void {\n if (!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 (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 acquire<R>(acquireOptions: AcquireOptions, fn?: (slot: TSlot) => R | Promise<R>): Promise<R | TSlot> {\n const { priority, signal } = acquireOptions;\n\n if (signal?.aborted) return Promise.reject(abortError(signal));\n\n return (async () => {\n for (;;) {\n if (terminated) throw new FamiliarTerminatedError();\n\n if (drainPromise) throw new FamiliarTerminatedError('Worker is draining');\n\n if (options.maxQueue === undefined || waiters.length < options.maxQueue) {\n return admit(acquireOptions, (fn ?? ((slot) => slot)) as (slot: TSlot) => R | Promise<R>);\n }\n\n if (options.onFull === 'reject') throw new FamiliarQueueFullError(options.maxQueue);\n\n await waitForCapacity(signal, priority);\n\n if (signal?.aborted) {\n releaseCapacity();\n throw abortError(signal);\n }\n }\n })();\n }\n\n function admit<R>(acquireOptions: AcquireOptions, fn: (slot: TSlot) => R | Promise<R>): Promise<R> {\n const { priority, signal } = acquireOptions;\n\n const free = freeSlots.pop();\n\n if (free) {\n try {\n return Promise.resolve(fn(free));\n } catch (error) {\n // A synchronous throw must not strand the slot: idle would never settle.\n release(free);\n settleIdle();\n\n return Promise.reject(error);\n }\n }\n\n return new Promise<R>((resolve, reject) => {\n const waiter: SlotWaiter<TSlot> = {\n cleanup() {\n waiter.signal?.removeEventListener('abort', onAbort);\n },\n priority,\n reject(reason) {\n waiter.cleanup();\n\n const index = waiters.indexOf(waiter);\n\n if (index !== -1) {\n waiters.splice(index, 1);\n releaseCapacity();\n }\n\n reject(reason);\n settleIdle();\n },\n sequence: waiterSequence++,\n signal,\n start(slot) {\n waiter.cleanup();\n\n try {\n resolve(fn(slot));\n } catch (error) {\n release(slot);\n settleIdle();\n reject(error);\n }\n },\n };\n const onAbort = () => waiter.reject(abortError(waiter.signal!));\n\n waiter.signal?.addEventListener('abort', onAbort, { once: true });\n waiters.push(waiter);\n waiters.sort((a, b) => b.priority - a.priority || a.sequence - b.sequence);\n });\n }\n\n function release(slot: TSlot): void {\n const next = waiters.shift();\n\n if (next) {\n next.start(slot);\n releaseCapacity();\n } else {\n freeSlots.push(slot);\n }\n }\n\n function dispose(): void {\n if (terminated) return;\n\n terminated = true;\n disposalController.abort();\n\n for (const slot of slots) slot.terminate();\n\n for (const waiter of waiters.splice(0)) waiter.reject(new FamiliarTerminatedError());\n\n rejectCapacity(new FamiliarTerminatedError());\n settleIdle();\n tappers.emit({ type: 'dispose' });\n tappers.clear();\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 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 return {\n acquire,\n disposalSignal: disposalController.signal,\n dispose,\n get disposed() {\n return terminated;\n },\n drain,\n get drainPromise() {\n return drainPromise;\n },\n emitTap(event) {\n tappers.emit(event);\n },\n release,\n settleIdle,\n stats() {\n return { active, completed, failed, queued: waiters.length + capacityWaiters.length };\n },\n status() {\n if (terminated) return 'terminated';\n\n return active === 0 ? 'idle' : 'running';\n },\n tap(handler, tapOptions) {\n if (terminated) return () => undefined;\n\n return tappers.tap(handler, tapOptions);\n },\n trackActive(delta: number) {\n active += delta;\n },\n trackCompleted() {\n completed += 1;\n },\n trackFailed() {\n failed += 1;\n },\n };\n}\n"],"mappings":"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"}
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");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;
1
+ const e=require("./errors.cjs"),t=require("./_pool-core.cjs");let n=require("@vielzeug/arsenal");function createPool(r,i){let a=t.createPoolCore(r,i);for(let e of r)e.notify=e=>a.emitTap({error:e,type:`worker-error`});function run(r,o={}){let s,c,l;try{s=t.validatePriority(o.priority??0),c=t.validateTimeout(o.timeout)??i.defaultTimeout,l=[...o.transferables??[]]}catch(e){return Promise.reject(e)}return a.acquire({priority:s,signal:o.signal},t=>{a.trackActive(1);let onAbort=()=>t.cancel((0,n.abortError)(o.signal));o.signal?.addEventListener(`abort`,onAbort,{once:!0});let finish=async()=>{try{let e=await t.run(r,l,c);return a.trackCompleted(),e}catch(t){throw!o.signal?.aborted&&!(t instanceof e.FamiliarTerminatedError)&&a.trackFailed(),t}finally{o.signal?.removeEventListener(`abort`,onAbort),a.trackActive(-1),a.release(t),a.settleIdle()}};return finish()})}return{get disposalSignal(){return a.disposalSignal},dispose:a.dispose,get disposed(){return a.disposed},drain:a.drain,run,get stats(){return a.stats()},get status(){return a.status()},tap:a.tap,[Symbol.asyncDispose]:()=>a.drain({}),[Symbol.dispose]:a.dispose}}function runBatch(t,r,i={}){let a,iterate=async function*(e){let a=[],onAbort=()=>e.abort(i.signal?.reason);i.signal?.aborted?e.abort(i.signal.reason):i.signal?.addEventListener(`abort`,onAbort,{once:!0});try{for(let[n,o]of r.entries()){let r=t.run(o,{priority:i.priority,signal:e.signal,timeout:i.timeout,transferables:i.getTransferables?.(o,n)}).catch(t=>{throw e.abort(t),t});r.catch(()=>void 0),a.push(r)}if(a.length===0&&e.signal.aborted)throw(0,n.abortError)(e.signal);for(let t of a){if(e.signal.aborted)throw(0,n.abortError)(e.signal);let r=await t;if(e.signal.aborted)throw(0,n.abortError)(e.signal);yield r}}catch(t){throw e.abort(t),t}finally{i.signal?.removeEventListener(`abort`,onAbort),e.abort(new DOMException(`Batch consumer stopped`,`AbortError`)),await Promise.allSettled(a)}};return{[Symbol.asyncIterator](){let t={},n=new AbortController,r,start=()=>{if(a??=t,a===t)return r??=iterate(n),r};return{next:()=>start()?.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=start();if(!r)throw new e.FamiliarRuntimeError(`Worker batches can only be consumed once`);return n.abort(t),r.throw(t)}}}}}exports.createPool=createPool,exports.runBatch=runBatch;
2
2
  //# sourceMappingURL=_pool.cjs.map
@@ -1 +1 @@
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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"}
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 { 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: readonly SlotStrategy<TInput, TOutput>[],\n options: PoolOptions,\n): WorkerPool<TInput, TOutput> {\n const core: PoolCore<SlotStrategy<TInput, TOutput>> = createPoolCore(slots, options);\n\n for (const slot of slots) slot.notify = (error) => core.emitTap({ error, type: 'worker-error' });\n\n function run(input: TInput, runOptions: RunOptions = {}): Promise<TOutput> {\n let priority: number;\n let timeout: number | undefined;\n let transferables: Transferable[];\n\n try {\n priority = validatePriority(runOptions.priority ?? 0);\n timeout = validateTimeout(runOptions.timeout) ?? options.defaultTimeout;\n transferables = [...(runOptions.transferables ?? [])];\n } catch (error) {\n return Promise.reject(error);\n }\n\n return core.acquire({ priority, signal: runOptions.signal }, (slot) => {\n core.trackActive(1);\n\n const onAbort = () => slot.cancel(abortError(runOptions.signal!));\n runOptions.signal?.addEventListener('abort', onAbort, { once: true });\n\n const finish = async (): Promise<TOutput> => {\n try {\n const value = await slot.run(input, transferables, timeout);\n\n core.trackCompleted();\n\n return value;\n } catch (error) {\n if (!runOptions.signal?.aborted && !(error instanceof FamiliarTerminatedError)) core.trackFailed();\n\n throw error;\n } finally {\n runOptions.signal?.removeEventListener('abort', onAbort);\n core.trackActive(-1);\n core.release(slot);\n core.settleIdle();\n }\n };\n\n return finish();\n });\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();\n },\n get status() {\n return core.status();\n },\n tap: core.tap,\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,7 @@
1
1
  import { type PoolOptions } from './_pool-core.js';
2
2
  import type { RunOptions, SlotStrategy, WorkerPool } from './types.js';
3
3
  export type { PoolOptions } from './_pool-core.js';
4
- export declare function createPool<TInput, TOutput>(slots: SlotStrategy<TInput, TOutput>[], options: PoolOptions): WorkerPool<TInput, TOutput>;
4
+ export declare function createPool<TInput, TOutput>(slots: readonly SlotStrategy<TInput, TOutput>[], options: PoolOptions): WorkerPool<TInput, TOutput>;
5
5
  export type BatchOptions<TInput> = Pick<RunOptions, 'priority' | 'signal' | 'timeout'> & {
6
6
  getTransferables?: (input: TInput, index: number) => readonly Transferable[];
7
7
  };
@@ -1 +1 @@
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"}
1
+ {"version":3,"file":"_pool.d.ts","sourceRoot":"","sources":["../src/_pool.ts"],"names":[],"mappings":"AACA,OAAO,EAAiC,KAAK,WAAW,EAAqC,MAAM,iBAAiB,CAAC;AAErH,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,SAAS,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAC/C,OAAO,EAAE,WAAW,GACnB,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,CAmE7B;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"}
package/dist/_pool.js CHANGED
@@ -1,159 +1,2 @@
1
- import { FamiliarQueueFullError as e, FamiliarRuntimeError as t, FamiliarTerminatedError as n } from "./errors.js";
2
- import { createPoolCore as r, validatePriority as i, validateTimeout as a } from "./_pool-core.js";
3
- import { TaskQueue as o } from "./_queue.js";
4
- import { abortError as s } from "@vielzeug/arsenal";
5
- //#region src/_pool.ts
6
- function c(t, c) {
7
- let l = [...t], u = new o(), d = !1, f = r({
8
- isIdle: () => l.length === t.length && u.size === 0,
9
- onDispose() {
10
- for (let e of t) e.terminate();
11
- for (; u.size > 0;) {
12
- let e = u.shift();
13
- if (!e) break;
14
- e.cleanupAbort?.(), e.reject(new n());
15
- }
16
- },
17
- onDrainStart() {}
18
- });
19
- function p() {
20
- for (; u.size > 0;) {
21
- let e = u.shift();
22
- if (!e) break;
23
- if (e.signal?.aborted) {
24
- e.cleanupAbort?.(), e.reject(s(e.signal)), f.releaseCapacity();
25
- continue;
26
- }
27
- return e;
28
- }
29
- f.settleIdle();
30
- }
31
- function m() {
32
- if (!(d || f.disposed)) {
33
- for (d = !0; !f.disposed && l.length > 0 && u.size > 0;) {
34
- let e = p();
35
- if (!e) break;
36
- let t = e, r = l.pop(), i = t.timeout ?? c.defaultTimeout;
37
- f.trackActive(1), f.releaseCapacity();
38
- let a = () => {
39
- t.aborted = !0, r.cancel(s(t.signal));
40
- };
41
- t.cleanupAbort = () => {
42
- t.signal?.removeEventListener("abort", a), t.cleanupAbort = void 0;
43
- }, t.signal?.addEventListener("abort", a, { once: !0 }), r.run(t.input, t.transferables, i).then((e) => o(e), (e) => u(e));
44
- function o(e) {
45
- t.cleanupAbort?.(), l.push(r), f.trackActive(-1), f.trackCompleted(), t.resolve(e), m(), f.settleIdle();
46
- }
47
- function u(e) {
48
- t.cleanupAbort?.(), l.push(r), f.trackActive(-1), !t.aborted && !(e instanceof n) && f.trackFailed(), t.reject(e), m(), f.settleIdle();
49
- }
50
- }
51
- d = !1;
52
- }
53
- }
54
- async function h(t, r = {}) {
55
- let { signal: o } = r, l = i(r.priority ?? 0), d = a(r.timeout), p = [...r.transferables ?? []];
56
- if (f.disposed) throw new n();
57
- if (f.drainPromise) throw new n("Worker is draining");
58
- if (o?.aborted) throw s(o);
59
- for (; c.onFull === "wait" && c.maxQueue !== void 0 && u.size >= c.maxQueue;) {
60
- if (await f.waitForCapacity(o, l), f.disposed) throw new n();
61
- if (f.drainPromise) throw new n("Worker is draining");
62
- if (o?.aborted) throw f.releaseCapacity(), s(o);
63
- }
64
- let h, g, _ = new Promise((e, t) => {
65
- h = e, g = t;
66
- }), v = {
67
- input: t,
68
- priority: l,
69
- reject: g,
70
- resolve: h,
71
- signal: o,
72
- timeout: d,
73
- transferables: p
74
- };
75
- if (!u.enqueue(v, c.onFull === "wait" ? void 0 : c.maxQueue)) throw new e(c.maxQueue);
76
- if (o) {
77
- let e = () => {
78
- u.remove(v) && (v.cleanupAbort?.(), g(s(o)), f.releaseCapacity(), f.settleIdle());
79
- };
80
- v.cleanupAbort = () => {
81
- o.removeEventListener("abort", e), v.cleanupAbort = void 0;
82
- }, o.addEventListener("abort", e, { once: !0 });
83
- }
84
- return m(), _;
85
- }
86
- return {
87
- get disposalSignal() {
88
- return f.disposalSignal;
89
- },
90
- dispose: f.dispose,
91
- get disposed() {
92
- return f.disposed;
93
- },
94
- drain: f.drain,
95
- run: h,
96
- get stats() {
97
- return f.stats(u.size);
98
- },
99
- get status() {
100
- return f.status();
101
- },
102
- [Symbol.asyncDispose]: () => f.drain({}),
103
- [Symbol.dispose]: f.dispose
104
- };
105
- }
106
- function l(e, r, i = {}) {
107
- let a, o = async function* (t) {
108
- let n = [], a = () => t.abort(i.signal?.reason);
109
- i.signal?.aborted ? t.abort(i.signal.reason) : i.signal?.addEventListener("abort", a, { once: !0 });
110
- try {
111
- for (let [a, o] of r.entries()) {
112
- let r = e.run(o, {
113
- priority: i.priority,
114
- signal: t.signal,
115
- timeout: i.timeout,
116
- transferables: i.getTransferables?.(o, a)
117
- }).catch((e) => {
118
- throw t.abort(e), e;
119
- });
120
- r.catch(() => void 0), n.push(r);
121
- }
122
- if (n.length === 0 && t.signal.aborted) throw s(t.signal);
123
- for (let e of n) {
124
- if (t.signal.aborted) throw s(t.signal);
125
- let n = await e;
126
- if (t.signal.aborted) throw s(t.signal);
127
- yield n;
128
- }
129
- } catch (e) {
130
- throw t.abort(e), e;
131
- } finally {
132
- i.signal?.removeEventListener("abort", a), t.abort(new DOMException("Batch consumer stopped", "AbortError")), await Promise.allSettled(n);
133
- }
134
- };
135
- return { [Symbol.asyncIterator]() {
136
- let e = {}, r = new AbortController(), i, s = () => {
137
- if (a ??= e, a === e) return i ??= o(r), i;
138
- };
139
- return {
140
- next: () => s()?.next() ?? Promise.reject(new t("Worker batches can only be consumed once")),
141
- return: async (t) => !a || a !== e ? {
142
- done: !0,
143
- value: t
144
- } : (r.abort(new n("Batch consumer stopped")), i?.return(t) ?? {
145
- done: !0,
146
- value: t
147
- }),
148
- throw: async (e) => {
149
- let n = s();
150
- if (!n) throw new t("Worker batches can only be consumed once");
151
- return r.abort(e), n.throw(e);
152
- }
153
- };
154
- } };
155
- }
156
- //#endregion
157
- export { c as createPool, l as runBatch };
158
-
1
+ import{FamiliarRuntimeError as e,FamiliarTerminatedError as t}from"./errors.js";import{createPoolCore as n,validatePriority as r,validateTimeout as i}from"./_pool-core.js";import{abortError as a}from"@vielzeug/arsenal";function createPool(e,o){let s=n(e,o);for(let t of e)t.notify=e=>s.emitTap({error:e,type:`worker-error`});function run(e,n={}){let c,l,u;try{c=r(n.priority??0),l=i(n.timeout)??o.defaultTimeout,u=[...n.transferables??[]]}catch(e){return Promise.reject(e)}return s.acquire({priority:c,signal:n.signal},r=>{s.trackActive(1);let onAbort=()=>r.cancel(a(n.signal));n.signal?.addEventListener(`abort`,onAbort,{once:!0});let finish=async()=>{try{let t=await r.run(e,u,l);return s.trackCompleted(),t}catch(e){throw!n.signal?.aborted&&!(e instanceof t)&&s.trackFailed(),e}finally{n.signal?.removeEventListener(`abort`,onAbort),s.trackActive(-1),s.release(r),s.settleIdle()}};return finish()})}return{get disposalSignal(){return s.disposalSignal},dispose:s.dispose,get disposed(){return s.disposed},drain:s.drain,run,get stats(){return s.stats()},get status(){return s.status()},tap:s.tap,[Symbol.asyncDispose]:()=>s.drain({}),[Symbol.dispose]:s.dispose}}function runBatch(n,r,i={}){let o,iterate=async function*(e){let t=[],onAbort=()=>e.abort(i.signal?.reason);i.signal?.aborted?e.abort(i.signal.reason):i.signal?.addEventListener(`abort`,onAbort,{once:!0});try{for(let[a,o]of r.entries()){let r=n.run(o,{priority:i.priority,signal:e.signal,timeout:i.timeout,transferables:i.getTransferables?.(o,a)}).catch(t=>{throw e.abort(t),t});r.catch(()=>void 0),t.push(r)}if(t.length===0&&e.signal.aborted)throw a(e.signal);for(let n of t){if(e.signal.aborted)throw a(e.signal);let t=await n;if(e.signal.aborted)throw a(e.signal);yield t}}catch(t){throw e.abort(t),t}finally{i.signal?.removeEventListener(`abort`,onAbort),e.abort(new DOMException(`Batch consumer stopped`,`AbortError`)),await Promise.allSettled(t)}};return{[Symbol.asyncIterator](){let n={},r=new AbortController,i,start=()=>{if(o??=n,o===n)return i??=iterate(r),i};return{next:()=>start()?.next()??Promise.reject(new e(`Worker batches can only be consumed once`)),return:async e=>!o||o!==n?{done:!0,value:e}:(r.abort(new t(`Batch consumer stopped`)),i?.return(e)??{done:!0,value:e}),throw:async t=>{let n=start();if(!n)throw new e(`Worker batches can only be consumed once`);return r.abort(t),n.throw(t)}}}}}export{createPool,runBatch};
159
2
  //# sourceMappingURL=_pool.js.map