@bquery/bquery 1.8.2 → 1.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/README.md +255 -27
  2. package/dist/{a11y-DVBCy09c.js → a11y-DG2i4iZN.js} +3 -3
  3. package/dist/{a11y-DVBCy09c.js.map → a11y-DG2i4iZN.js.map} +1 -1
  4. package/dist/a11y.es.mjs +1 -1
  5. package/dist/{component-L3-JfOFz.js → component-DRotf1hl.js} +19 -18
  6. package/dist/{component-L3-JfOFz.js.map → component-DRotf1hl.js.map} +1 -1
  7. package/dist/component.es.mjs +1 -1
  8. package/dist/concurrency/errors.d.ts +29 -0
  9. package/dist/concurrency/errors.d.ts.map +1 -0
  10. package/dist/concurrency/high-level.d.ts +85 -0
  11. package/dist/concurrency/high-level.d.ts.map +1 -0
  12. package/dist/concurrency/index.d.ts +19 -0
  13. package/dist/concurrency/index.d.ts.map +1 -0
  14. package/dist/concurrency/internal.d.ts +26 -0
  15. package/dist/concurrency/internal.d.ts.map +1 -0
  16. package/dist/concurrency/pipeline.d.ts +30 -0
  17. package/dist/concurrency/pipeline.d.ts.map +1 -0
  18. package/dist/concurrency/pool.d.ts +48 -0
  19. package/dist/concurrency/pool.d.ts.map +1 -0
  20. package/dist/concurrency/reactive.d.ts +107 -0
  21. package/dist/concurrency/reactive.d.ts.map +1 -0
  22. package/dist/concurrency/rpc.d.ts +46 -0
  23. package/dist/concurrency/rpc.d.ts.map +1 -0
  24. package/dist/concurrency/support.d.ts +23 -0
  25. package/dist/concurrency/support.d.ts.map +1 -0
  26. package/dist/concurrency/task.d.ts +31 -0
  27. package/dist/concurrency/task.d.ts.map +1 -0
  28. package/dist/concurrency/types.d.ts +343 -0
  29. package/dist/concurrency/types.d.ts.map +1 -0
  30. package/dist/concurrency-BU1wPEsZ.js +826 -0
  31. package/dist/concurrency-BU1wPEsZ.js.map +1 -0
  32. package/dist/concurrency.es.mjs +29 -0
  33. package/dist/{constraints-D5RHQLmP.js → constraints-CqjhmpZC.js} +1 -1
  34. package/dist/{constraints-D5RHQLmP.js.map → constraints-CqjhmpZC.js.map} +1 -1
  35. package/dist/core-CongXJuo.js +87 -0
  36. package/dist/core-CongXJuo.js.map +1 -0
  37. package/dist/{custom-directives-Dr4C5lVV.js → custom-directives-BjFzFhuf.js} +1 -1
  38. package/dist/{custom-directives-Dr4C5lVV.js.map → custom-directives-BjFzFhuf.js.map} +1 -1
  39. package/dist/{devtools-BhB2iDPT.js → devtools-C5FExMwv.js} +2 -2
  40. package/dist/{devtools-BhB2iDPT.js.map → devtools-C5FExMwv.js.map} +1 -1
  41. package/dist/devtools.es.mjs +1 -1
  42. package/dist/{dnd-NwZBYh4l.js → dnd-BAqzPlSo.js} +1 -1
  43. package/dist/{dnd-NwZBYh4l.js.map → dnd-BAqzPlSo.js.map} +1 -1
  44. package/dist/dnd.es.mjs +1 -1
  45. package/dist/effect-Cc51IH91.js +87 -0
  46. package/dist/effect-Cc51IH91.js.map +1 -0
  47. package/dist/{env-CTdvLaH2.js → env-PvwYHnJq.js} +1 -1
  48. package/dist/{env-CTdvLaH2.js.map → env-PvwYHnJq.js.map} +1 -1
  49. package/dist/{forms-UcRHsYxC.js → forms-Dx1Scvh0.js} +30 -29
  50. package/dist/{forms-UcRHsYxC.js.map → forms-Dx1Scvh0.js.map} +1 -1
  51. package/dist/forms.es.mjs +1 -1
  52. package/dist/full.d.ts +6 -4
  53. package/dist/full.d.ts.map +1 -1
  54. package/dist/full.es.mjs +240 -206
  55. package/dist/full.iife.js +117 -33
  56. package/dist/full.iife.js.map +1 -1
  57. package/dist/full.umd.js +117 -33
  58. package/dist/full.umd.js.map +1 -1
  59. package/dist/{i18n-kuF6Ekj6.js → i18n-Cazyk9RD.js} +3 -3
  60. package/dist/{i18n-kuF6Ekj6.js.map → i18n-Cazyk9RD.js.map} +1 -1
  61. package/dist/i18n.es.mjs +1 -1
  62. package/dist/index.d.ts +1 -0
  63. package/dist/index.d.ts.map +1 -1
  64. package/dist/index.es.mjs +274 -240
  65. package/dist/media/index.d.ts +10 -3
  66. package/dist/media/index.d.ts.map +1 -1
  67. package/dist/media/observers.d.ts +99 -0
  68. package/dist/media/observers.d.ts.map +1 -0
  69. package/dist/media/types.d.ts +125 -0
  70. package/dist/media/types.d.ts.map +1 -1
  71. package/dist/media-dAKIGPk3.js +514 -0
  72. package/dist/media-dAKIGPk3.js.map +1 -0
  73. package/dist/media.es.mjs +12 -9
  74. package/dist/{motion-BJsAuULb.js → motion-BBMso9Ir.js} +1 -1
  75. package/dist/{motion-BJsAuULb.js.map → motion-BBMso9Ir.js.map} +1 -1
  76. package/dist/motion.es.mjs +1 -1
  77. package/dist/mount-C8O2vXkQ.js +450 -0
  78. package/dist/mount-C8O2vXkQ.js.map +1 -0
  79. package/dist/{platform-Dw2gE3zI.js → platform-BPHIXbw8.js} +17 -16
  80. package/dist/{platform-Dw2gE3zI.js.map → platform-BPHIXbw8.js.map} +1 -1
  81. package/dist/platform.es.mjs +1 -1
  82. package/dist/{plugin-C2WuC8SF.js → plugin-DjTqWg-P.js} +2 -2
  83. package/dist/{plugin-C2WuC8SF.js.map → plugin-DjTqWg-P.js.map} +1 -1
  84. package/dist/plugin.es.mjs +1 -1
  85. package/dist/reactive/index.d.ts +2 -2
  86. package/dist/reactive/index.d.ts.map +1 -1
  87. package/dist/reactive/signal.d.ts +2 -1
  88. package/dist/reactive/signal.d.ts.map +1 -1
  89. package/dist/reactive/watch.d.ts +49 -0
  90. package/dist/reactive/watch.d.ts.map +1 -1
  91. package/dist/reactive/websocket.d.ts +6 -3
  92. package/dist/reactive/websocket.d.ts.map +1 -1
  93. package/dist/reactive-BAd2hfl8.js +1171 -0
  94. package/dist/reactive-BAd2hfl8.js.map +1 -0
  95. package/dist/reactive.es.mjs +41 -37
  96. package/dist/readonly-C0ZwS1Tf.js +35 -0
  97. package/dist/readonly-C0ZwS1Tf.js.map +1 -0
  98. package/dist/{registry-B08iilIh.js → registry-Cr6VH8CR.js} +1 -1
  99. package/dist/{registry-B08iilIh.js.map → registry-Cr6VH8CR.js.map} +1 -1
  100. package/dist/{router-CQikC9Ed.js → router-CCepRMpC.js} +29 -28
  101. package/dist/{router-CQikC9Ed.js.map → router-CCepRMpC.js.map} +1 -1
  102. package/dist/router.es.mjs +1 -1
  103. package/dist/{ssr-_dAcGdzu.js → ssr-D-1IPcfw.js} +4 -4
  104. package/dist/{ssr-_dAcGdzu.js.map → ssr-D-1IPcfw.js.map} +1 -1
  105. package/dist/ssr.es.mjs +1 -1
  106. package/dist/{store-Cb3gPRve.js → store-CjmEeX9-.js} +6 -6
  107. package/dist/{store-Cb3gPRve.js.map → store-CjmEeX9-.js.map} +1 -1
  108. package/dist/store.es.mjs +2 -2
  109. package/dist/{testing-C5Sjfsna.js → testing-TdfaL7VE.js} +8 -8
  110. package/dist/{testing-C5Sjfsna.js.map → testing-TdfaL7VE.js.map} +1 -1
  111. package/dist/testing.es.mjs +1 -1
  112. package/dist/{untrack-D0fnO5k2.js → untrack-bjWDNdyE.js} +11 -10
  113. package/dist/{untrack-D0fnO5k2.js.map → untrack-bjWDNdyE.js.map} +1 -1
  114. package/dist/view/directives/aria.d.ts +7 -0
  115. package/dist/view/directives/aria.d.ts.map +1 -0
  116. package/dist/view/directives/error.d.ts +7 -0
  117. package/dist/view/directives/error.d.ts.map +1 -0
  118. package/dist/view/directives/index.d.ts +2 -0
  119. package/dist/view/directives/index.d.ts.map +1 -1
  120. package/dist/view/mount.d.ts.map +1 -1
  121. package/dist/view/process.d.ts +2 -0
  122. package/dist/view/process.d.ts.map +1 -1
  123. package/dist/view.es.mjs +12 -11
  124. package/package.json +18 -14
  125. package/src/concurrency/errors.ts +57 -0
  126. package/src/concurrency/high-level.ts +387 -0
  127. package/src/concurrency/index.ts +63 -0
  128. package/src/concurrency/internal.ts +100 -0
  129. package/src/concurrency/pipeline.ts +133 -0
  130. package/src/concurrency/pool.ts +450 -0
  131. package/src/concurrency/reactive.ts +339 -0
  132. package/src/concurrency/rpc.ts +380 -0
  133. package/src/concurrency/support.ts +44 -0
  134. package/src/concurrency/task.ts +318 -0
  135. package/src/concurrency/types.ts +431 -0
  136. package/src/full.ts +77 -0
  137. package/src/index.ts +3 -0
  138. package/src/media/index.ts +20 -2
  139. package/src/media/observers.ts +418 -0
  140. package/src/media/types.ts +136 -0
  141. package/src/reactive/index.ts +3 -0
  142. package/src/reactive/signal.ts +2 -1
  143. package/src/reactive/watch.ts +138 -0
  144. package/src/reactive/websocket.ts +31 -8
  145. package/src/view/directives/aria.ts +72 -0
  146. package/src/view/directives/error.ts +56 -0
  147. package/src/view/directives/index.ts +2 -0
  148. package/src/view/mount.ts +4 -0
  149. package/src/view/process.ts +6 -0
  150. package/dist/core-DdtZHzsS.js +0 -168
  151. package/dist/core-DdtZHzsS.js.map +0 -1
  152. package/dist/media-i-fB5WxI.js +0 -340
  153. package/dist/media-i-fB5WxI.js.map +0 -1
  154. package/dist/mount-B4Y8bk8Z.js +0 -403
  155. package/dist/mount-B4Y8bk8Z.js.map +0 -1
  156. package/dist/reactive-DwkhUJfP.js +0 -1148
  157. package/dist/reactive-DwkhUJfP.js.map +0 -1
@@ -0,0 +1,450 @@
1
+ /**
2
+ * Worker pools with bounded concurrency and explicit queueing.
3
+ *
4
+ * @module bquery/concurrency
5
+ */
6
+
7
+ import { TaskWorkerAbortError, TaskWorkerError } from './errors';
8
+ import { createRpcWorker } from './rpc';
9
+ import { createTaskWorker } from './task';
10
+ import type {
11
+ CreateRpcPoolOptions,
12
+ CreateTaskPoolOptions,
13
+ RpcPool,
14
+ RpcWorker,
15
+ TaskPool,
16
+ TaskRunOptions,
17
+ TaskWorker,
18
+ TaskWorkerState,
19
+ WorkerRpcHandlers,
20
+ WorkerTaskHandler,
21
+ } from './types';
22
+
23
+ const DEFAULT_POOL_CONCURRENCY = 4;
24
+
25
+ interface QueueEntry<TJob, TResult> {
26
+ abortHandler?: () => void;
27
+ job: TJob;
28
+ options: TaskRunOptions;
29
+ reject: (reason?: unknown) => void;
30
+ resolve: (value: TResult | PromiseLike<TResult>) => void;
31
+ signal?: AbortSignal;
32
+ }
33
+
34
+ interface PoolRuntime<TJob, TResult> {
35
+ readonly state: TaskWorkerState;
36
+ readonly busy: boolean;
37
+ readonly concurrency: number;
38
+ readonly pending: number;
39
+ readonly size: number;
40
+ enqueue(job: TJob, options?: TaskRunOptions): Promise<TResult>;
41
+ clear(): void;
42
+ terminate(): void;
43
+ }
44
+
45
+ interface CreatePoolRuntimeOptions<TWorker extends { busy: boolean }, TJob, TResult> {
46
+ abortedWhileQueuedMessage: string;
47
+ clearMessage: string;
48
+ concurrency: number;
49
+ createWorkers: (concurrency: number) => TWorker[];
50
+ queueFullMessage: string;
51
+ terminatedMessage: string;
52
+ workerTerminatedMessage: string;
53
+ runWorker: (worker: TWorker, job: TJob, options: TaskRunOptions) => Promise<TResult>;
54
+ maxQueue: number;
55
+ }
56
+
57
+ const normalizeConcurrency = (concurrency: number | undefined, label: string): number => {
58
+ if (concurrency === undefined) {
59
+ return DEFAULT_POOL_CONCURRENCY;
60
+ }
61
+
62
+ if (!Number.isInteger(concurrency) || concurrency < 1) {
63
+ throw new RangeError(`${label} concurrency must be a positive integer.`);
64
+ }
65
+
66
+ return concurrency;
67
+ };
68
+
69
+ const normalizeMaxQueue = (maxQueue: number | undefined, label: string): number => {
70
+ if (maxQueue === undefined) {
71
+ return Number.POSITIVE_INFINITY;
72
+ }
73
+
74
+ if (maxQueue === Number.POSITIVE_INFINITY) {
75
+ return maxQueue;
76
+ }
77
+
78
+ if (!Number.isInteger(maxQueue) || maxQueue < 0) {
79
+ throw new RangeError(`${label} maxQueue must be a non-negative integer or Infinity.`);
80
+ }
81
+
82
+ return maxQueue;
83
+ };
84
+
85
+ const detachAbortListener = <TJob, TResult>(entry: QueueEntry<TJob, TResult>): void => {
86
+ if (entry.abortHandler && entry.signal) {
87
+ entry.signal.removeEventListener('abort', entry.abortHandler);
88
+ }
89
+
90
+ entry.abortHandler = undefined;
91
+ entry.signal = undefined;
92
+ };
93
+
94
+ const createPoolRuntime = <TWorker extends { busy: boolean }, TJob, TResult>({
95
+ abortedWhileQueuedMessage,
96
+ clearMessage,
97
+ concurrency,
98
+ createWorkers,
99
+ queueFullMessage,
100
+ terminatedMessage,
101
+ workerTerminatedMessage,
102
+ runWorker,
103
+ maxQueue,
104
+ }: CreatePoolRuntimeOptions<TWorker, TJob, TResult>): PoolRuntime<TJob, TResult> => {
105
+ const queue: Array<QueueEntry<TJob, TResult>> = [];
106
+ const workers = createWorkers(concurrency);
107
+ let disposed = false;
108
+ let running = 0;
109
+
110
+ const drain = (): void => {
111
+ if (disposed || queue.length === 0) {
112
+ return;
113
+ }
114
+
115
+ for (const worker of workers) {
116
+ if (queue.length === 0) {
117
+ return;
118
+ }
119
+
120
+ if (worker.busy) {
121
+ continue;
122
+ }
123
+
124
+ const entry = queue.shift()!;
125
+ if (entry.signal?.aborted) {
126
+ detachAbortListener(entry);
127
+ entry.reject(new TaskWorkerAbortError(abortedWhileQueuedMessage));
128
+ continue;
129
+ }
130
+
131
+ detachAbortListener(entry);
132
+ running++;
133
+ void runWorker(worker, entry.job, entry.options)
134
+ .then(entry.resolve, entry.reject)
135
+ .finally(() => {
136
+ running--;
137
+ drain();
138
+ });
139
+ }
140
+ };
141
+
142
+ const rejectQueued = (error: TaskWorkerError): void => {
143
+ const queued = queue.splice(0);
144
+ for (const entry of queued) {
145
+ detachAbortListener(entry);
146
+ entry.reject(error);
147
+ }
148
+ };
149
+
150
+ return {
151
+ get state(): TaskWorkerState {
152
+ if (disposed) {
153
+ return 'terminated';
154
+ }
155
+
156
+ return running > 0 || queue.length > 0 ? 'running' : 'idle';
157
+ },
158
+ get busy(): boolean {
159
+ return running > 0 || queue.length > 0;
160
+ },
161
+ concurrency,
162
+ get pending(): number {
163
+ return running;
164
+ },
165
+ get size(): number {
166
+ return queue.length;
167
+ },
168
+ enqueue(job: TJob, options: TaskRunOptions = {}): Promise<TResult> {
169
+ if (disposed) {
170
+ return Promise.reject(new TaskWorkerError(workerTerminatedMessage, 'TERMINATED'));
171
+ }
172
+
173
+ if (options.signal?.aborted) {
174
+ return Promise.reject(new TaskWorkerAbortError());
175
+ }
176
+
177
+ return new Promise<TResult>((resolve, reject) => {
178
+ const entry: QueueEntry<TJob, TResult> = {
179
+ job,
180
+ options,
181
+ reject,
182
+ resolve,
183
+ };
184
+
185
+ const idleWorker = workers.find((worker) => !worker.busy);
186
+ if (idleWorker) {
187
+ running++;
188
+ void runWorker(idleWorker, job, options)
189
+ .then(resolve, reject)
190
+ .finally(() => {
191
+ running--;
192
+ drain();
193
+ });
194
+ return;
195
+ }
196
+
197
+ if (queue.length >= maxQueue) {
198
+ reject(new TaskWorkerError(queueFullMessage, 'QUEUE_FULL'));
199
+ return;
200
+ }
201
+
202
+ if (options.signal) {
203
+ entry.signal = options.signal;
204
+ entry.abortHandler = () => {
205
+ const index = queue.indexOf(entry);
206
+ if (index === -1) {
207
+ return;
208
+ }
209
+
210
+ queue.splice(index, 1);
211
+ detachAbortListener(entry);
212
+ reject(new TaskWorkerAbortError(abortedWhileQueuedMessage));
213
+ };
214
+ options.signal.addEventListener('abort', entry.abortHandler, { once: true });
215
+ }
216
+
217
+ queue.push(entry);
218
+ });
219
+ },
220
+ clear(): void {
221
+ if (disposed || queue.length === 0) {
222
+ return;
223
+ }
224
+
225
+ rejectQueued(new TaskWorkerError(clearMessage, 'QUEUE_CLEARED'));
226
+ },
227
+ terminate(): void {
228
+ if (disposed) {
229
+ return;
230
+ }
231
+
232
+ disposed = true;
233
+ rejectQueued(new TaskWorkerError(terminatedMessage, 'TERMINATED'));
234
+ for (const worker of workers) {
235
+ if ('terminate' in worker && typeof worker.terminate === 'function') {
236
+ worker.terminate();
237
+ }
238
+ }
239
+ },
240
+ };
241
+ };
242
+
243
+ const createWorkerNames = (
244
+ name: string | undefined,
245
+ concurrency: number
246
+ ): Array<string | undefined> => {
247
+ if (!name) {
248
+ return Array.from({ length: concurrency }, () => undefined);
249
+ }
250
+
251
+ if (concurrency === 1) {
252
+ return [name];
253
+ }
254
+
255
+ return Array.from({ length: concurrency }, (_, index) => `${name}-${index + 1}`);
256
+ };
257
+
258
+ /**
259
+ * Creates a reusable pool of task workers with bounded concurrency and FIFO queueing.
260
+ *
261
+ * @example
262
+ * ```ts
263
+ * import { createTaskPool } from '@bquery/bquery/concurrency';
264
+ *
265
+ * const pool = createTaskPool(
266
+ * ({ value }: { value: number }) => value * 2,
267
+ * { concurrency: 4, maxQueue: 16, name: 'double-pool' }
268
+ * );
269
+ *
270
+ * const results = await Promise.all([
271
+ * pool.run({ value: 1 }),
272
+ * pool.run({ value: 2 }),
273
+ * pool.run({ value: 3 }),
274
+ * ]);
275
+ *
276
+ * pool.terminate();
277
+ * ```
278
+ */
279
+ export function createTaskPool<TInput = void, TResult = unknown>(
280
+ handler: WorkerTaskHandler<TInput, TResult>,
281
+ options: CreateTaskPoolOptions = {}
282
+ ): TaskPool<TInput, TResult> {
283
+ const { concurrency: concurrencyOption, maxQueue: maxQueueOption, ...workerOptions } = options;
284
+ const concurrency = normalizeConcurrency(concurrencyOption, 'Task pool');
285
+ const maxQueue = normalizeMaxQueue(maxQueueOption, 'Task pool');
286
+
287
+ const runtime = createPoolRuntime<TaskWorker<TInput, TResult>, TInput, TResult>({
288
+ abortedWhileQueuedMessage: 'The queued task was aborted before execution started.',
289
+ clearMessage: 'The task pool queue was cleared.',
290
+ concurrency,
291
+ createWorkers(poolConcurrency) {
292
+ const workers: Array<TaskWorker<TInput, TResult>> = [];
293
+ const names = createWorkerNames(workerOptions.name, poolConcurrency);
294
+
295
+ try {
296
+ for (let index = 0; index < poolConcurrency; index++) {
297
+ workers.push(
298
+ createTaskWorker(handler, {
299
+ ...workerOptions,
300
+ name: names[index],
301
+ })
302
+ );
303
+ }
304
+ } catch (error) {
305
+ for (const worker of workers) {
306
+ worker.terminate();
307
+ }
308
+ throw error;
309
+ }
310
+
311
+ return workers;
312
+ },
313
+ queueFullMessage:
314
+ 'The task pool queue is full. Increase maxQueue, wait for pending tasks, or raise pool concurrency.',
315
+ terminatedMessage: 'The task pool was terminated.',
316
+ workerTerminatedMessage: 'The task pool has already been terminated.',
317
+ runWorker(worker, job, runOptions) {
318
+ return worker.run(job, runOptions);
319
+ },
320
+ maxQueue,
321
+ });
322
+
323
+ return {
324
+ get state(): TaskWorkerState {
325
+ return runtime.state;
326
+ },
327
+ get busy(): boolean {
328
+ return runtime.busy;
329
+ },
330
+ get concurrency(): number {
331
+ return runtime.concurrency;
332
+ },
333
+ get pending(): number {
334
+ return runtime.pending;
335
+ },
336
+ get size(): number {
337
+ return runtime.size;
338
+ },
339
+ run(input: TInput, runOptions?: TaskRunOptions): Promise<TResult> {
340
+ return runtime.enqueue(input, runOptions);
341
+ },
342
+ clear(): void {
343
+ runtime.clear();
344
+ },
345
+ terminate(): void {
346
+ runtime.terminate();
347
+ },
348
+ };
349
+ }
350
+
351
+ /**
352
+ * Creates a reusable pool of RPC workers with bounded concurrency and FIFO queueing.
353
+ *
354
+ * @example
355
+ * ```ts
356
+ * import { createRpcPool } from '@bquery/bquery/concurrency';
357
+ *
358
+ * const pool = createRpcPool(
359
+ * {
360
+ * sum: ({ values }: { values: number[] }) => values.reduce((total, value) => total + value, 0),
361
+ * },
362
+ * { concurrency: 2, maxQueue: 8 }
363
+ * );
364
+ *
365
+ * const total = await pool.call('sum', { values: [1, 2, 3] });
366
+ * pool.terminate();
367
+ * ```
368
+ */
369
+ export function createRpcPool<TRoutes extends WorkerRpcHandlers>(
370
+ handlers: TRoutes,
371
+ options: CreateRpcPoolOptions = {}
372
+ ): RpcPool<TRoutes> {
373
+ const { concurrency: concurrencyOption, maxQueue: maxQueueOption, ...workerOptions } = options;
374
+ const concurrency = normalizeConcurrency(concurrencyOption, 'RPC pool');
375
+ const maxQueue = normalizeMaxQueue(maxQueueOption, 'RPC pool');
376
+
377
+ type RpcJob = {
378
+ input: unknown;
379
+ method: keyof TRoutes & string;
380
+ };
381
+
382
+ const runtime = createPoolRuntime<RpcWorker<TRoutes>, RpcJob, unknown>({
383
+ abortedWhileQueuedMessage: 'The queued RPC call was aborted before execution started.',
384
+ clearMessage: 'The RPC pool queue was cleared.',
385
+ concurrency,
386
+ createWorkers(poolConcurrency) {
387
+ const workers: Array<RpcWorker<TRoutes>> = [];
388
+ const names = createWorkerNames(workerOptions.name, poolConcurrency);
389
+
390
+ try {
391
+ for (let index = 0; index < poolConcurrency; index++) {
392
+ workers.push(
393
+ createRpcWorker(handlers, {
394
+ ...workerOptions,
395
+ name: names[index],
396
+ })
397
+ );
398
+ }
399
+ } catch (error) {
400
+ for (const worker of workers) {
401
+ worker.terminate();
402
+ }
403
+ throw error;
404
+ }
405
+
406
+ return workers;
407
+ },
408
+ queueFullMessage:
409
+ 'The RPC pool queue is full. Increase maxQueue, wait for pending calls, or raise pool concurrency.',
410
+ terminatedMessage: 'The RPC pool was terminated.',
411
+ workerTerminatedMessage: 'The RPC pool has already been terminated.',
412
+ runWorker(worker, job, runOptions) {
413
+ return worker.call(job.method, job.input as never, runOptions);
414
+ },
415
+ maxQueue,
416
+ });
417
+
418
+ return {
419
+ get state(): TaskWorkerState {
420
+ return runtime.state;
421
+ },
422
+ get busy(): boolean {
423
+ return runtime.busy;
424
+ },
425
+ get concurrency(): number {
426
+ return runtime.concurrency;
427
+ },
428
+ get pending(): number {
429
+ return runtime.pending;
430
+ },
431
+ get size(): number {
432
+ return runtime.size;
433
+ },
434
+ call<TMethod extends keyof TRoutes & string>(
435
+ method: TMethod,
436
+ input: Parameters<TRoutes[TMethod]>[0],
437
+ runOptions?: TaskRunOptions
438
+ ): Promise<Awaited<ReturnType<TRoutes[TMethod]>>> {
439
+ return runtime.enqueue({ input, method }, runOptions) as Promise<
440
+ Awaited<ReturnType<TRoutes[TMethod]>>
441
+ >;
442
+ },
443
+ clear(): void {
444
+ runtime.clear();
445
+ },
446
+ terminate(): void {
447
+ runtime.terminate();
448
+ },
449
+ };
450
+ }