performance-helpers 1.0.0 → 1.0.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 (287) hide show
  1. package/README.md +12 -2
  2. package/package.json +146 -1
  3. package/src/index.js +1 -0
  4. package/.eslintrc.cjs +0 -22
  5. package/.nojekyll +0 -0
  6. package/.prettierrc +0 -6
  7. package/CONTRIBUTING.md +0 -178
  8. package/assets/1_Caching.md +0 -4
  9. package/assets/2_Parallelizing.md +0 -18
  10. package/assets/3_Logging.md +0 -3
  11. package/assets/404.md +0 -3
  12. package/assets/4_Utils.md +0 -10
  13. package/assets/logo.png +0 -0
  14. package/assets/navigation.md +0 -10
  15. package/bench/README.md +0 -97
  16. package/bench/results.json +0 -94
  17. package/bench/results.md +0 -233
  18. package/bench/run.js +0 -2639
  19. package/bench/worker.js +0 -43
  20. package/docs/README.md +0 -38
  21. package/docs/docs-typedoc.json +0 -38714
  22. package/docs/helpers/constants/README.md +0 -34
  23. package/docs/helpers/constants/variables/DEFAULT_AUTOSCALE_BACKOFF_MAX_MULTIPLIER.md +0 -9
  24. package/docs/helpers/constants/variables/DEFAULT_AUTOSCALE_COOLDOWN_MS.md +0 -9
  25. package/docs/helpers/constants/variables/DEFAULT_AUTOSCALE_INTERVAL_MS.md +0 -9
  26. package/docs/helpers/constants/variables/DEFAULT_AUTOSCALE_MIN_INTERVAL_MS.md +0 -9
  27. package/docs/helpers/constants/variables/DEFAULT_BACKPRESSURE_QUEUE_CAPACITY.md +0 -9
  28. package/docs/helpers/constants/variables/DEFAULT_BACKPRESSURE_REFILL_INTERVAL_MS.md +0 -9
  29. package/docs/helpers/constants/variables/DEFAULT_BATCH_MAX_SIZE.md +0 -9
  30. package/docs/helpers/constants/variables/DEFAULT_CACHE_DEFAULT_TTL_MS.md +0 -9
  31. package/docs/helpers/constants/variables/DEFAULT_CACHE_MAX_POOL_SIZE.md +0 -9
  32. package/docs/helpers/constants/variables/DEFAULT_CACHE_MAX_WEIGHT_BYTES.md +0 -9
  33. package/docs/helpers/constants/variables/DEFAULT_HISTOGRAM_BUCKET_COUNT.md +0 -9
  34. package/docs/helpers/constants/variables/DEFAULT_HISTOGRAM_MAX_VALUE.md +0 -9
  35. package/docs/helpers/constants/variables/DEFAULT_MAX_CLEANUP_PER_TICK.md +0 -9
  36. package/docs/helpers/constants/variables/DEFAULT_QUEUE_CAPACITY.md +0 -9
  37. package/docs/helpers/constants/variables/DEFAULT_REAPER_MIN_INTERVAL_MS.md +0 -9
  38. package/docs/helpers/constants/variables/DEFAULT_REFILL_INTERVAL_MS.md +0 -9
  39. package/docs/helpers/constants/variables/DEFAULT_RETRY_BASE_DELAY_MS.md +0 -9
  40. package/docs/helpers/constants/variables/DEFAULT_RETRY_MAX_DELAY_MS.md +0 -9
  41. package/docs/helpers/constants/variables/DEFAULT_TIMEOUT_MS.md +0 -9
  42. package/docs/helpers/constants/variables/ENCODE_CACHE_LARGE_KEY_LENGTH.md +0 -9
  43. package/docs/helpers/constants/variables/MAX_DEEP_EQUAL_DEPTH.md +0 -9
  44. package/docs/helpers/constants/variables/MS_PER_MIN.md +0 -9
  45. package/docs/helpers/constants/variables/MS_PER_SEC.md +0 -9
  46. package/docs/helpers/constants/variables/default.md +0 -103
  47. package/docs/helpers/jsdoc-types/README.md +0 -33
  48. package/docs/helpers/jsdoc-types/interfaces/BufferDecoder.md +0 -23
  49. package/docs/helpers/jsdoc-types/interfaces/BufferEncoder.md +0 -23
  50. package/docs/helpers/jsdoc-types/interfaces/CacheNode.md +0 -43
  51. package/docs/helpers/jsdoc-types/interfaces/CommonPoolOptions.md +0 -31
  52. package/docs/helpers/jsdoc-types/interfaces/PendingResponseEntry.md +0 -51
  53. package/docs/helpers/jsdoc-types/interfaces/PostMessageOptions.md +0 -39
  54. package/docs/helpers/jsdoc-types/interfaces/PowerBatchOptions.md +0 -13
  55. package/docs/helpers/jsdoc-types/interfaces/PowerCacheOptions.md +0 -115
  56. package/docs/helpers/jsdoc-types/interfaces/PowerChunkingOptions.md +0 -31
  57. package/docs/helpers/jsdoc-types/interfaces/PowerCircuitOptions.md +0 -45
  58. package/docs/helpers/jsdoc-types/interfaces/PowerDeadlineOptions.md +0 -101
  59. package/docs/helpers/jsdoc-types/interfaces/PowerDeferOptions.md +0 -13
  60. package/docs/helpers/jsdoc-types/interfaces/PowerEventBusOptions.md +0 -19
  61. package/docs/helpers/jsdoc-types/interfaces/PowerLatchOptions.md +0 -23
  62. package/docs/helpers/jsdoc-types/interfaces/PowerLoggerOptions.md +0 -51
  63. package/docs/helpers/jsdoc-types/interfaces/PowerObserverOptions.md +0 -25
  64. package/docs/helpers/jsdoc-types/interfaces/PowerPoolOptions.md +0 -85
  65. package/docs/helpers/jsdoc-types/interfaces/PowerQueueOptions.md +0 -13
  66. package/docs/helpers/jsdoc-types/interfaces/PowerRetryOptions.md +0 -83
  67. package/docs/helpers/jsdoc-types/interfaces/PowerSlidingWindowOptions.md +0 -19
  68. package/docs/helpers/jsdoc-types/interfaces/PowerTTLMapOptions.md +0 -27
  69. package/docs/helpers/jsdoc-types/interfaces/PowerThrottleOptions.md +0 -31
  70. package/docs/helpers/jsdoc-types/interfaces/WorkerObj.md +0 -55
  71. package/docs/helpers/powerBackpressure/README.md +0 -17
  72. package/docs/helpers/powerBackpressure/classes/PowerBackpressure.md +0 -368
  73. package/docs/helpers/powerBatch/README.md +0 -17
  74. package/docs/helpers/powerBatch/classes/PowerBatch.md +0 -139
  75. package/docs/helpers/powerBuffer/README.md +0 -26
  76. package/docs/helpers/powerBuffer/functions/b2o.md +0 -25
  77. package/docs/helpers/powerBuffer/functions/o2b.md +0 -23
  78. package/docs/helpers/powerBuffer/functions/o2u8.md +0 -33
  79. package/docs/helpers/powerBuffer/functions/u82o.md +0 -30
  80. package/docs/helpers/powerBulkhead/README.md +0 -17
  81. package/docs/helpers/powerBulkhead/classes/PowerBulkhead.md +0 -302
  82. package/docs/helpers/powerCache/README.md +0 -29
  83. package/docs/helpers/powerCache/classes/PowerCache.md +0 -933
  84. package/docs/helpers/powerCache/classes/PowerMemoizer.md +0 -244
  85. package/docs/helpers/powerCache/classes/PowerTimedCache.md +0 -302
  86. package/docs/helpers/powerCache/functions/simpleArgsKey.md +0 -31
  87. package/docs/helpers/powerChunking/README.md +0 -17
  88. package/docs/helpers/powerChunking/classes/PowerChunker.md +0 -78
  89. package/docs/helpers/powerCircuit/README.md +0 -23
  90. package/docs/helpers/powerCircuit/classes/PowerCircuit.md +0 -167
  91. package/docs/helpers/powerDeadline/README.md +0 -23
  92. package/docs/helpers/powerDeadline/classes/PowerDeadline.md +0 -88
  93. package/docs/helpers/powerDefer/README.md +0 -17
  94. package/docs/helpers/powerDefer/classes/PowerDefer.md +0 -134
  95. package/docs/helpers/powerEventBus/README.md +0 -23
  96. package/docs/helpers/powerEventBus/classes/PowerEventBus.md +0 -330
  97. package/docs/helpers/powerHistogram/README.md +0 -17
  98. package/docs/helpers/powerHistogram/classes/PowerHistogram.md +0 -285
  99. package/docs/helpers/powerLatch/README.md +0 -17
  100. package/docs/helpers/powerLatch/classes/PowerLatch.md +0 -264
  101. package/docs/helpers/powerLogger/README.md +0 -17
  102. package/docs/helpers/powerLogger/classes/PowerLogger.md +0 -290
  103. package/docs/helpers/powerObserver/README.md +0 -23
  104. package/docs/helpers/powerObserver/classes/PowerObserver.md +0 -213
  105. package/docs/helpers/powerPermitGate/README.md +0 -11
  106. package/docs/helpers/powerPermitGate/classes/PowerPermitGate.md +0 -248
  107. package/docs/helpers/powerPool/README.md +0 -36
  108. package/docs/helpers/powerPool/classes/PowerPool.md +0 -973
  109. package/docs/helpers/powerPool/classes/PowerPoolShutdownError.md +0 -67
  110. package/docs/helpers/powerQueue/README.md +0 -11
  111. package/docs/helpers/powerQueue/classes/PowerQueue.md +0 -302
  112. package/docs/helpers/powerRateLimit/README.md +0 -17
  113. package/docs/helpers/powerRateLimit/classes/PowerRateLimit.md +0 -187
  114. package/docs/helpers/powerRetry/README.md +0 -23
  115. package/docs/helpers/powerRetry/classes/PowerRetry.md +0 -106
  116. package/docs/helpers/powerScheduler/README.md +0 -11
  117. package/docs/helpers/powerScheduler/classes/PowerScheduler.md +0 -135
  118. package/docs/helpers/powerSemaphore/README.md +0 -17
  119. package/docs/helpers/powerSemaphore/classes/PowerSemaphore.md +0 -173
  120. package/docs/helpers/powerSlidingWindow/README.md +0 -11
  121. package/docs/helpers/powerSlidingWindow/classes/PowerSlidingWindow.md +0 -83
  122. package/docs/helpers/powerSubscriberSet/README.md +0 -15
  123. package/docs/helpers/powerSubscriberSet/classes/PowerSubscriberSet.md +0 -251
  124. package/docs/helpers/powerSubscriberSet/functions/cleanupWeakRefs.md +0 -21
  125. package/docs/helpers/powerTTLMap/README.md +0 -17
  126. package/docs/helpers/powerTTLMap/classes/PowerTTLMap.md +0 -326
  127. package/docs/helpers/powerThrottle/README.md +0 -17
  128. package/docs/helpers/powerThrottle/classes/PowerThrottle.md +0 -216
  129. package/docs/index/README.md +0 -205
  130. package/docs/utils/errors/README.md +0 -12
  131. package/docs/utils/errors/functions/formatErrorObj.md +0 -30
  132. package/docs/utils/errors/functions/normalizeError.md +0 -50
  133. package/docs/utils/now/README.md +0 -19
  134. package/docs/utils/now/functions/measureAsync.md +0 -37
  135. package/docs/utils/now/functions/measureSync.md +0 -54
  136. package/docs/utils/now/functions/nowMs.md +0 -24
  137. package/guides/autoscale.md +0 -80
  138. package/guides/errors.md +0 -41
  139. package/guides/metaGuide.md +0 -440
  140. package/guides/now.md +0 -56
  141. package/guides/powerBackpressure.md +0 -110
  142. package/guides/powerBatch.md +0 -82
  143. package/guides/powerBuffer.md +0 -86
  144. package/guides/powerBulkhead.md +0 -61
  145. package/guides/powerCache.md +0 -269
  146. package/guides/powerChunking.md +0 -130
  147. package/guides/powerCircuit.md +0 -84
  148. package/guides/powerDeadline.md +0 -99
  149. package/guides/powerDefer.md +0 -56
  150. package/guides/powerEventBus.md +0 -89
  151. package/guides/powerHistogram.md +0 -71
  152. package/guides/powerLatch.md +0 -94
  153. package/guides/powerLogger.md +0 -129
  154. package/guides/powerObserver.md +0 -65
  155. package/guides/powerPermitGate.md +0 -52
  156. package/guides/powerPool.md +0 -321
  157. package/guides/powerQueue.md +0 -112
  158. package/guides/powerRateLimit.md +0 -37
  159. package/guides/powerRetry.md +0 -54
  160. package/guides/powerScheduler.md +0 -41
  161. package/guides/powerSemaphore.md +0 -65
  162. package/guides/powerSlidingWindow.md +0 -63
  163. package/guides/powerSubscriberSet.md +0 -48
  164. package/guides/powerTTLMap.md +0 -58
  165. package/guides/powerThrottle.md +0 -152
  166. package/index.html +0 -57
  167. package/results.json +0 -6692
  168. package/scripts/find-missing-jsdoc.js +0 -62
  169. package/scripts/modernize-optional-chaining.cjs +0 -36
  170. package/scripts/pool-debug.mjs +0 -29
  171. package/scripts/repro_powercache.js +0 -14
  172. package/scripts/static-audit-exports.cjs +0 -93
  173. package/scripts/static-audit-exports.json +0 -518
  174. package/test/powerBackpressure.test.js +0 -114
  175. package/test/powerBatch.branches.extra.test.js +0 -122
  176. package/test/powerBatch.test.js +0 -79
  177. package/test/powerBuffer.test.js +0 -125
  178. package/test/powerBulkhead.test.js +0 -210
  179. package/test/powerCache.branches.test.js +0 -233
  180. package/test/powerCache.bulk.test.js +0 -31
  181. package/test/powerCache.getorset.test.js +0 -110
  182. package/test/powerCache.hitRate.test.js +0 -35
  183. package/test/powerCache.inflight.test.js +0 -24
  184. package/test/powerCache.iterator.test.js +0 -18
  185. package/test/powerCache.misses.test.js +0 -52
  186. package/test/powerCache.more.test.js +0 -118
  187. package/test/powerCache.test.js +0 -37
  188. package/test/powerCache.timeout.test.js +0 -25
  189. package/test/powerCache.touch.test.js +0 -46
  190. package/test/powerChunking.branches.extra.test.js +0 -155
  191. package/test/powerChunking.errors.test.js +0 -177
  192. package/test/powerChunking.test.js +0 -39
  193. package/test/powerCircuit.observability.test.js +0 -71
  194. package/test/powerCircuit.test.js +0 -74
  195. package/test/powerDeadline.test.js +0 -140
  196. package/test/powerDefer.test.js +0 -55
  197. package/test/powerErrors.test.js +0 -32
  198. package/test/powerEventBus.branches.extra.test.js +0 -70
  199. package/test/powerEventBus.extra.test.js +0 -72
  200. package/test/powerEventBus.max.test.js +0 -43
  201. package/test/powerEventBus.more.test.js +0 -121
  202. package/test/powerEventBus.once_off.test.js +0 -17
  203. package/test/powerEventBus.test.js +0 -74
  204. package/test/powerEventBus.uncovered.test.js +0 -57
  205. package/test/powerEventBus.weak.test.js +0 -18
  206. package/test/powerHistogram.test.js +0 -73
  207. package/test/powerLatch.branches.extra.test.js +0 -115
  208. package/test/powerLatch.test.js +0 -57
  209. package/test/powerLogger.branches.test.js +0 -98
  210. package/test/powerLogger.formatter.name.test.js +0 -58
  211. package/test/powerLogger.json.test.js +0 -88
  212. package/test/powerLogger.output.test.js +0 -81
  213. package/test/powerLogger.table.debug.test.js +0 -77
  214. package/test/powerLogger.test.js +0 -59
  215. package/test/powerMemoizer.memoize.test.js +0 -100
  216. package/test/powerMemoizer.test.js +0 -85
  217. package/test/powerObserver.test.js +0 -129
  218. package/test/powerPermitGate.test.js +0 -66
  219. package/test/powerPool.autoTransfer.test.js +0 -100
  220. package/test/powerPool.autoscale.extra.test.js +0 -88
  221. package/test/powerPool.autoscale.test.js +0 -136
  222. package/test/powerPool.awaitDefaultTimeout.test.js +0 -52
  223. package/test/powerPool.awaitTimeout.test.js +0 -22
  224. package/test/powerPool.batch.test.js +0 -170
  225. package/test/powerPool.branches.extra2.test.js +0 -42
  226. package/test/powerPool.branches.test.js +0 -102
  227. package/test/powerPool.browser.messageerror.test.js +0 -45
  228. package/test/powerPool.correlation.test.js +0 -26
  229. package/test/powerPool.correlationId.test.js +0 -63
  230. package/test/powerPool.dispose.test.js +0 -49
  231. package/test/powerPool.drain.test.js +0 -57
  232. package/test/powerPool.events.test.js +0 -131
  233. package/test/powerPool.more.extra.test.js +0 -99
  234. package/test/powerPool.more.test.js +0 -283
  235. package/test/powerPool.node.messageerror.test.js +0 -46
  236. package/test/powerPool.postMessage.promise.test.js +0 -83
  237. package/test/powerPool.queueHigh.test.js +0 -55
  238. package/test/powerPool.queueSaturation.test.js +0 -51
  239. package/test/powerPool.rapidResize.test.js +0 -55
  240. package/test/powerPool.resize.overload.test.js +0 -65
  241. package/test/powerPool.resize.test.js +0 -70
  242. package/test/powerPool.shutdown.test.js +0 -38
  243. package/test/powerPool.stats.test.js +0 -40
  244. package/test/powerPool.stopThePress.test.js +0 -94
  245. package/test/powerPool.terminateShutdown.test.js +0 -22
  246. package/test/powerPool.test.js +0 -525
  247. package/test/powerPool.timers.test.js +0 -55
  248. package/test/powerPool.uncovered.test.js +0 -407
  249. package/test/powerPool.workerId.test.js +0 -47
  250. package/test/powerQueue.iterators.test.js +0 -67
  251. package/test/powerQueue.saturation.test.js +0 -18
  252. package/test/powerQueue.test.js +0 -48
  253. package/test/powerQueue.unshiftMany.test.js +0 -49
  254. package/test/powerRateLimit.atomic.test.js +0 -80
  255. package/test/powerRateLimit.extra.test.js +0 -145
  256. package/test/powerRateLimit.functions.test.js +0 -106
  257. package/test/powerRateLimit.test.js +0 -38
  258. package/test/powerRetry.attemptTimeout.test.js +0 -51
  259. package/test/powerRetry.test.js +0 -121
  260. package/test/powerScheduler.test.js +0 -126
  261. package/test/powerSemaphore.test.js +0 -108
  262. package/test/powerSlidingWindow.pool.test.js +0 -55
  263. package/test/powerSlidingWindow.test.js +0 -25
  264. package/test/powerSubscriberSet.test.js +0 -125
  265. package/test/powerTTLMap.test.js +0 -125
  266. package/test/powerThrottle.pool.test.js +0 -54
  267. package/test/powerThrottle.refill.test.js +0 -22
  268. package/test/powerThrottle.reserve.test.js +0 -46
  269. package/test/powerThrottle.test.js +0 -45
  270. package/test/powerTimedCache.test.js +0 -73
  271. package/test/umd.bundle.branches.test.js +0 -100
  272. package/test/umd.bundle.cache-timers.test.js +0 -48
  273. package/test/umd.bundle.exhaustive.test.js +0 -158
  274. package/test/umd.bundle.fuzz.test.js +0 -86
  275. package/test/umd.bundle.hasEqual.more.test.js +0 -68
  276. package/test/umd.bundle.hasEqual.test.js +0 -104
  277. package/test/umd.bundle.logger-extra.test.js +0 -48
  278. package/test/umd.bundle.more-coverage-2.test.js +0 -67
  279. package/test/umd.bundle.pool.test.js +0 -134
  280. package/test/umd.bundle.test.js +0 -265
  281. package/test/utils.measure.test.js +0 -49
  282. package/test/utils.now.extra.test.js +0 -30
  283. package/test/utils.now.more.test.js +0 -57
  284. package/tsconfig.json +0 -16
  285. package/typedoc.json +0 -25
  286. package/vite.config.js +0 -31
  287. package/vitest.config.js +0 -17
@@ -1,525 +0,0 @@
1
- import { describe, it, expect, vi } from 'vitest';
2
- import { PowerPool } from '../src/helpers/powerPool.js';
3
-
4
- describe('PowerPool (mocked worker)', () => {
5
- it('forwards plain object messages as transferable Uint8Array and decodes responses', async () => {
6
- // Mock worker constructor
7
- class MockUnderlying {
8
- constructor() {
9
- this.onmessage = null;
10
- this.onerror = null;
11
- this.onmessageerror = null;
12
- this.postMessage = vi.fn((msg) => {
13
- // simulate a worker processing and replying with the same message
14
- setTimeout(() => {
15
- if (this.onmessage) this.onmessage({ data: msg });
16
- }, 0);
17
- });
18
- this.terminate = vi.fn();
19
- }
20
- addEventListener(type, cb) {
21
- if (type === 'message') this.onmessage = cb;
22
- if (type === 'error') this.onerror = cb;
23
- if (type === 'messageerror') this.onmessageerror = cb;
24
- }
25
- removeEventListener() {}
26
- }
27
-
28
- const pool = new PowerPool(MockUnderlying, { size: 1, idleTimeout: 1000 });
29
- try {
30
- const p = new Promise((resolve) => {
31
- pool.onmessage = (e) => {
32
- // the pool should deliver a decoded object
33
- resolve(e.data);
34
- };
35
- });
36
-
37
- const sent = { hello: 'world' };
38
- const ok = pool.postMessage(sent);
39
- expect(ok).toBe(true);
40
-
41
- // ensure underlying.postMessage received a Uint8Array
42
- const underlying = pool.workers[0]._underlying || pool.workers[0].worker._underlying || null;
43
- // Try a few strategies to locate the underlying mock
44
- const post =
45
- underlying && underlying.postMessage
46
- ? underlying.postMessage
47
- : pool.workers[0].worker._underlying && pool.workers[0].worker._underlying.postMessage;
48
- // wait for reply
49
- const decoded = await p;
50
- expect(decoded).toEqual(sent);
51
- if (post) {
52
- const callArg = post.mock.calls[0][0];
53
- // the callArg should be a Uint8Array when posting an object
54
- expect(callArg).toBeInstanceOf(Uint8Array);
55
- }
56
- } finally {
57
- pool.terminate();
58
- }
59
- });
60
-
61
- it('supports arrow-function worker factories', () => {
62
- class MockUnderlying {
63
- constructor() {
64
- this.onmessage = null;
65
- this.postMessage = vi.fn();
66
- this.terminate = vi.fn();
67
- }
68
- addEventListener(type, cb) {
69
- if (type === 'message') this.onmessage = cb;
70
- }
71
- removeEventListener() {}
72
- }
73
-
74
- const pool = new PowerPool(() => new MockUnderlying(), { size: 1, idleTimeout: 1000 });
75
- try {
76
- expect(pool.workers.length).toBeGreaterThanOrEqual(1);
77
- pool.postMessage({ x: 42 });
78
- expect(pool.workers[0].tasks).toBeGreaterThanOrEqual(1);
79
- } finally {
80
- pool.terminate();
81
- }
82
- });
83
-
84
- it('broadcasts to all workers and increments tasks', () => {
85
- class MockUnderlying {
86
- constructor() {
87
- this.onmessage = null;
88
- this.postMessage = vi.fn();
89
- this.terminate = vi.fn();
90
- }
91
- }
92
- // ensure eager creation for this test by setting minSize == size
93
- const pool = new PowerPool(MockUnderlying, { size: 2, minSize: 2, idleTimeout: 1000 });
94
- try {
95
- pool.broadcast({ b: 1 });
96
- expect(pool.workers.length).toBe(2);
97
- for (const w of pool.workers) {
98
- // underlying should have been invoked via wrapper
99
- const underlying = w.worker._underlying || w.worker._underlying;
100
- expect(underlying.postMessage).toHaveBeenCalled();
101
- expect(w.tasks).toBeGreaterThanOrEqual(1);
102
- }
103
- } finally {
104
- pool.terminate();
105
- }
106
- });
107
-
108
- it('lazy defaults to true and only creates minSize workers at construction', () => {
109
- class MockUnderlying {
110
- constructor() {
111
- this.onmessage = null;
112
- this.postMessage = vi.fn();
113
- this.terminate = vi.fn();
114
- }
115
- }
116
- // default lazy should be true; with size:4 and default minSize 1 at least one worker exists
117
- const pool = new PowerPool(MockUnderlying, { size: 4, maxSize: 4, idleTimeout: 1000 });
118
- try {
119
- expect(pool.workers.length).toBe(pool.minSize);
120
- // grow by posting tasks: pool should create more workers up to maxSize
121
- pool.postMessage({ x: 1 });
122
- pool.postMessage({ x: 2 });
123
- // after a short tick the pool may have grown; at least one worker should exist
124
- expect(pool.workers.length).toBeGreaterThanOrEqual(1);
125
- } finally {
126
- pool.terminate();
127
- }
128
- });
129
-
130
- it('addWorker and removeWorker manage workers', () => {
131
- class MockUnderlying {
132
- constructor() {
133
- this.onmessage = null;
134
- this.postMessage = vi.fn();
135
- this.terminate = vi.fn();
136
- }
137
- }
138
- const pool = new PowerPool(MockUnderlying, { size: 1, minSize: 0 });
139
- try {
140
- const before = pool.workers.length;
141
- pool.addWorker();
142
- expect(pool.workers.length).toBe(before + 1);
143
- pool.removeWorker();
144
- // removeWorker terminates last worker; length decreases or equals before
145
- expect(pool.workers.length).toBe(before);
146
- } finally {
147
- pool.terminate();
148
- }
149
- });
150
-
151
- it('queues tasks when all workers busy and dispatches when free', async () => {
152
- class SlowUnderlying {
153
- constructor() {
154
- this.onmessage = null;
155
- this.postMessage = vi.fn((msg) => {
156
- // reply after a small delay
157
- setTimeout(() => {
158
- if (this.onmessage) this.onmessage({ data: msg });
159
- }, 20);
160
- });
161
- this.terminate = vi.fn();
162
- }
163
- }
164
- const pool = new PowerPool(SlowUnderlying, {
165
- size: 1,
166
- maxSize: 1,
167
- maxTasksPerWorker: 1,
168
- idleTimeout: 1000,
169
- taskQueue: true,
170
- });
171
- try {
172
- const received = [];
173
- pool.onmessage = (e) => received.push(e.data);
174
-
175
- // post multiple messages; with maxTasksPerWorker=1 the second should be queued
176
- expect(pool.postMessage({ n: 1 })).toBe(true);
177
- expect(pool.postMessage({ n: 2 })).toBe(true);
178
- // queueing may be implementation-dependent under lazy growth; verify eventual delivery
179
-
180
- // wait for both messages to be processed
181
- await new Promise((res) => setTimeout(res, 100));
182
- expect(received.length).toBeGreaterThanOrEqual(2);
183
- expect(pool.queue.length).toBe(0);
184
- } finally {
185
- pool.terminate();
186
- }
187
- });
188
-
189
- it('does not use the internal queue for a single-worker pool with infinite capacity', async () => {
190
- class SlowUnderlying {
191
- constructor() {
192
- this.onmessage = null;
193
- this.postMessage = vi.fn((msg) => {
194
- setTimeout(() => {
195
- if (this.onmessage) this.onmessage({ data: msg });
196
- }, 20);
197
- });
198
- this.terminate = vi.fn();
199
- }
200
- }
201
- const pool = new PowerPool(SlowUnderlying, {
202
- size: 1,
203
- minSize: 1,
204
- maxSize: 1,
205
- idleTimeout: 1000,
206
- taskQueue: true,
207
- lazy: false,
208
- });
209
- try {
210
- const received = [];
211
- pool.onmessage = (e) => {
212
- if (e && e.data && typeof e.data.n === 'number') received.push(e.data);
213
- };
214
-
215
- expect(pool.postMessage({ n: 1 })).toBe(true);
216
- expect(pool.postMessage({ n: 2 })).toBe(true);
217
- expect(pool.queue.length).toBe(0);
218
-
219
- await new Promise((res) => setTimeout(res, 100));
220
- expect(received.length).toBe(2);
221
- expect(pool.queue.length).toBe(0);
222
- } finally {
223
- pool.terminate();
224
- }
225
- });
226
-
227
- it('drops the newest queued task when queuePolicy is drop-newest', async () => {
228
- class SlowUnderlying {
229
- constructor() {
230
- this.onmessage = null;
231
- this.postMessage = vi.fn((msg) => {
232
- setTimeout(() => {
233
- if (this.onmessage) this.onmessage({ data: msg });
234
- }, 20);
235
- });
236
- this.terminate = vi.fn();
237
- }
238
- }
239
- const pool = new PowerPool(SlowUnderlying, {
240
- size: 1,
241
- minSize: 1,
242
- maxSize: 1,
243
- maxTasksPerWorker: 1,
244
- idleTimeout: 1000,
245
- taskQueue: true,
246
- queuePolicy: 'drop-newest',
247
- lazy: false,
248
- });
249
- try {
250
- const received = [];
251
- pool.onmessage = (e) => {
252
- if (e && e.data && typeof e.data.n === 'number') received.push(e.data);
253
- };
254
-
255
- expect(pool.postMessage({ n: 1 })).toBe(true);
256
- expect(pool.postMessage({ n: 2 })).toBe(true);
257
- expect(pool.postMessage({ n: 3 })).toBe(false);
258
-
259
- await new Promise((res) => setTimeout(res, 120));
260
- expect(received).toEqual([{ n: 1 }, { n: 2 }]);
261
- expect(pool.queue.length).toBe(0);
262
- } finally {
263
- pool.terminate();
264
- }
265
- });
266
-
267
- it('drops the oldest queued task when queuePolicy is drop-oldest', async () => {
268
- class SlowUnderlying {
269
- constructor() {
270
- this.onmessage = null;
271
- this.postMessage = vi.fn((msg) => {
272
- setTimeout(() => {
273
- if (this.onmessage) this.onmessage({ data: msg });
274
- }, 20);
275
- });
276
- this.terminate = vi.fn();
277
- }
278
- }
279
- const pool = new PowerPool(SlowUnderlying, {
280
- size: 1,
281
- minSize: 1,
282
- maxSize: 1,
283
- maxTasksPerWorker: 1,
284
- idleTimeout: 1000,
285
- taskQueue: true,
286
- queuePolicy: 'drop-oldest',
287
- lazy: false,
288
- });
289
- try {
290
- const received = [];
291
- pool.onmessage = (e) => {
292
- if (e && e.data && typeof e.data.n === 'number') received.push(e.data);
293
- };
294
-
295
- expect(pool.postMessage({ n: 1 })).toBe(true);
296
- expect(pool.postMessage({ n: 2 })).toBe(true);
297
- expect(pool.postMessage({ n: 3 })).toBe(true);
298
-
299
- await new Promise((res) => setTimeout(res, 120));
300
- expect(received).toEqual([{ n: 1 }, { n: 3 }]);
301
- expect(pool.queue.length).toBe(0);
302
- } finally {
303
- pool.terminate();
304
- }
305
- });
306
-
307
- it('rejects queued tasks when queuePolicy is reject', async () => {
308
- class SlowUnderlying {
309
- constructor() {
310
- this.onmessage = null;
311
- this.postMessage = vi.fn((msg) => {
312
- setTimeout(() => {
313
- if (this.onmessage) this.onmessage({ data: msg });
314
- }, 20);
315
- });
316
- this.terminate = vi.fn();
317
- }
318
- }
319
- const pool = new PowerPool(SlowUnderlying, {
320
- size: 1,
321
- minSize: 1,
322
- maxSize: 1,
323
- maxTasksPerWorker: 1,
324
- idleTimeout: 1000,
325
- taskQueue: true,
326
- queuePolicy: 'reject',
327
- lazy: false,
328
- });
329
- try {
330
- expect(pool.postMessage({ n: 1 })).toBe(true);
331
- const rejected = pool.postMessage({ n: 2 }, undefined, { awaitResponse: true, timeout: 100 });
332
- await expect(rejected).rejects.toThrow(/queue policy/);
333
- } finally {
334
- pool.terminate();
335
- }
336
- });
337
-
338
- it('pauses queued dispatch until resumed', async () => {
339
- class SlowUnderlying {
340
- constructor() {
341
- this.onmessage = null;
342
- this.postMessage = vi.fn((msg) => {
343
- setTimeout(() => {
344
- if (this.onmessage) this.onmessage({ data: msg });
345
- }, 20);
346
- });
347
- this.terminate = vi.fn();
348
- }
349
- }
350
- const pool = new PowerPool(SlowUnderlying, {
351
- size: 1,
352
- minSize: 1,
353
- maxSize: 1,
354
- maxTasksPerWorker: 1,
355
- idleTimeout: 1000,
356
- taskQueue: true,
357
- });
358
- try {
359
- const received = [];
360
- pool.onmessage = (e) => {
361
- if (e && e.data && typeof e.data.n === 'number') received.push(e.data);
362
- };
363
- expect(pool.queuePaused).toBe(false);
364
- pool.pauseQueue();
365
- expect(pool.queuePaused).toBe(true);
366
-
367
- expect(pool.postMessage({ n: 1 })).toBe(true);
368
- expect(pool.postMessage({ n: 2 })).toBe(true);
369
- expect(pool.queue.length).toBe(1);
370
-
371
- await new Promise((res) => setTimeout(res, 80));
372
- expect(received).toEqual([{ n: 1 }]);
373
- expect(pool.queue.length).toBe(1);
374
-
375
- pool.resumeQueue();
376
- expect(pool.queuePaused).toBe(false);
377
- await new Promise((res) => setTimeout(res, 80));
378
- expect(received).toEqual([{ n: 1 }, { n: 2 }]);
379
- expect(pool.queue.length).toBe(0);
380
- } finally {
381
- pool.terminate();
382
- }
383
- });
384
-
385
- it('supports pause() / resume() aliases for queue control', async () => {
386
- class SlowUnderlying {
387
- constructor() {
388
- this.onmessage = null;
389
- this.postMessage = vi.fn((msg) => {
390
- setTimeout(() => {
391
- if (this.onmessage) this.onmessage({ data: msg });
392
- }, 20);
393
- });
394
- this.terminate = vi.fn();
395
- }
396
- }
397
- const pool = new PowerPool(SlowUnderlying, {
398
- size: 1,
399
- minSize: 1,
400
- maxSize: 1,
401
- maxTasksPerWorker: 1,
402
- idleTimeout: 1000,
403
- taskQueue: true,
404
- });
405
- try {
406
- const received = [];
407
- pool.onmessage = (e) => {
408
- if (e && e.data && typeof e.data.n === 'number') received.push(e.data);
409
- };
410
- pool.pause();
411
- expect(pool.queuePaused).toBe(true);
412
-
413
- expect(pool.postMessage({ n: 1 })).toBe(true);
414
- expect(pool.postMessage({ n: 2 })).toBe(true);
415
- expect(pool.queue.length).toBe(1);
416
-
417
- await new Promise((res) => setTimeout(res, 80));
418
- expect(received).toEqual([{ n: 1 }]);
419
- expect(pool.queue.length).toBe(1);
420
-
421
- pool.resume();
422
- expect(pool.queuePaused).toBe(false);
423
- await new Promise((res) => setTimeout(res, 80));
424
- expect(received).toEqual([{ n: 1 }, { n: 2 }]);
425
- expect(pool.queue.length).toBe(0);
426
- } finally {
427
- pool.terminate();
428
- }
429
- });
430
-
431
- it('emits idle event when transitioning to idle', async () => {
432
- class MockUnderlying {
433
- constructor() {
434
- this.onmessage = null;
435
- this.postMessage = vi.fn((msg) => {
436
- setTimeout(() => {
437
- if (this.onmessage) this.onmessage({ data: msg });
438
- }, 10);
439
- });
440
- this.terminate = vi.fn();
441
- }
442
- }
443
- const pool = new PowerPool(MockUnderlying, { size: 1, idleTimeout: 1000 });
444
- try {
445
- let idleCalled = false;
446
- pool.onidle = () => {
447
- idleCalled = true;
448
- };
449
- // pool is idle initially; assign onidle should invoke immediately per setter
450
- expect(idleCalled).toBe(true);
451
-
452
- idleCalled = false;
453
- // now post a task and wait for idle to reoccur
454
- pool.postMessage({ x: 1 });
455
- await new Promise((res) => setTimeout(res, 50));
456
- expect(idleCalled).toBe(true);
457
- } finally {
458
- pool.terminate();
459
- }
460
- });
461
-
462
- it('stopThePress clears lifecycle timers when recreateWorkers is false', () => {
463
- class MockUnderlying {
464
- constructor() {
465
- this.onmessage = null;
466
- this.postMessage = vi.fn();
467
- this.terminate = vi.fn();
468
- }
469
- addEventListener(type, cb) {
470
- if (type === 'message') this.onmessage = cb;
471
- if (type === 'error') this.onerror = cb;
472
- if (type === 'messageerror') this.onmessageerror = cb;
473
- }
474
- removeEventListener() {}
475
- }
476
-
477
- const pool = new PowerPool(MockUnderlying, {
478
- size: 1,
479
- minSize: 1,
480
- idleTimeout: 1000,
481
- autoScale: { intervalMs: 100, targetMs: 10, alpha: 0.5 },
482
- });
483
- try {
484
- expect(pool._reaperInterval).not.toBeNull();
485
- expect(pool._autoScaleInterval).not.toBeNull();
486
- pool.stopThePress({ action: 'flush' }, undefined, { recreateWorkers: false });
487
- expect(pool._reaperInterval).toBeNull();
488
- expect(pool._autoScaleInterval).toBeNull();
489
- } finally {
490
- pool.terminate();
491
- }
492
- });
493
-
494
- it('stopThePressBatch clears lifecycle timers when recreateWorkers is false', () => {
495
- class MockUnderlying {
496
- constructor() {
497
- this.onmessage = null;
498
- this.postMessage = vi.fn();
499
- this.terminate = vi.fn();
500
- }
501
- addEventListener(type, cb) {
502
- if (type === 'message') this.onmessage = cb;
503
- if (type === 'error') this.onerror = cb;
504
- if (type === 'messageerror') this.onmessageerror = cb;
505
- }
506
- removeEventListener() {}
507
- }
508
-
509
- const pool = new PowerPool(MockUnderlying, {
510
- size: 1,
511
- minSize: 1,
512
- idleTimeout: 1000,
513
- autoScale: { intervalMs: 100, targetMs: 10, alpha: 0.5 },
514
- });
515
- try {
516
- expect(pool._reaperInterval).not.toBeNull();
517
- expect(pool._autoScaleInterval).not.toBeNull();
518
- pool.stopThePressBatch([{ message: { action: 'batch' } }], { recreateWorkers: false });
519
- expect(pool._reaperInterval).toBeNull();
520
- expect(pool._autoScaleInterval).toBeNull();
521
- } finally {
522
- pool.terminate();
523
- }
524
- });
525
- });
@@ -1,55 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { PowerPool } from '../src/helpers/powerPool.js';
3
-
4
- // Minimal fake worker that supports addEventListener/postMessage/terminate
5
- class FakeWorker {
6
- constructor() {
7
- this._handlers = {};
8
- }
9
- addEventListener(name, cb) {
10
- this._handlers[name] = cb;
11
- }
12
- removeEventListener(name) {
13
- delete this._handlers[name];
14
- }
15
- postMessage(msg) {
16
- // echo back a simple response asynchronously
17
- setTimeout(() => {
18
- const h = this._handlers['message'];
19
- if (h) h({ data: msg });
20
- }, 0);
21
- }
22
- terminate() {}
23
- }
24
-
25
- describe('PowerPool timers and id stability', () => {
26
- it('clears reaper and autoscale intervals on stopThePress(recreate=false)', () => {
27
- const p = new PowerPool(FakeWorker, {
28
- lazy: false,
29
- minSize: 1,
30
- size: 1,
31
- autoScale: { intervalMs: 100, targetMs: 10 },
32
- });
33
- // initially intervals exist (reaper always, autoscale created)
34
- expect(p._reaperInterval).toBeTruthy();
35
- expect(p._autoScaleInterval).toBeTruthy();
36
-
37
- // stop and request no recreation -> intervals should be cleared
38
- p.stopThePress({ msg: 'x' }, undefined, { recreateWorkers: false });
39
- expect(p._reaperInterval).toBeNull();
40
- expect(p._autoScaleInterval).toBeNull();
41
- });
42
-
43
- it('generates monotonic worker ids across remove/add cycles', () => {
44
- const p = new PowerPool(FakeWorker, { lazy: false, minSize: 1, size: 1 });
45
- // add and remove
46
- const added = p.addWorker();
47
- const addedId = added.id;
48
- p.removeWorker();
49
- const newWorker = p.addWorker();
50
- // new id should not equal the previous added id (monotonic allocator)
51
- expect(newWorker.id).not.toBe(addedId);
52
- // ensure internal _nextWorkerId progressed beyond last seen id
53
- expect(p._nextWorkerId).toBeGreaterThanOrEqual(newWorker.id + 1);
54
- });
55
- });