web-csv-toolbox 0.13.0-next-7d51d5285be9cffa5103de58469d8de0c98959d7 → 0.13.0-next-b21b6d89a7a3f18dcbf79ec04ffefde0d7ff4c4c
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -6
- package/dist/CSVLexer.js.map +1 -1
- package/dist/CSVLexerTransformer.js.map +1 -1
- package/dist/CSVRecordAssembler.js.map +1 -1
- package/dist/CSVRecordAssemblerTransformer.js.map +1 -1
- package/dist/_virtual/web_csv_toolbox_wasm_bg.wasm.js +1 -1
- package/dist/assertCommonOptions.js.map +1 -1
- package/dist/common/constants.js.map +1 -1
- package/dist/common/errors.js.map +1 -1
- package/dist/common/types.d.ts +311 -14
- package/dist/commonParseErrorHandling.js.map +1 -1
- package/dist/constants.js.map +1 -1
- package/dist/createWorker.node.d.ts +2 -0
- package/dist/createWorker.web.d.ts +2 -0
- package/dist/execution/EnginePresets.d.ts +143 -0
- package/dist/execution/EnginePresets.js +129 -0
- package/dist/execution/EnginePresets.js.map +1 -0
- package/dist/execution/InternalEngineConfig.d.ts +89 -0
- package/dist/execution/InternalEngineConfig.js +175 -0
- package/dist/execution/InternalEngineConfig.js.map +1 -0
- package/dist/execution/main/parseBinaryInMain.d.ts +12 -0
- package/dist/execution/main/parseStreamInMain.d.ts +12 -0
- package/dist/execution/main/parseStringInMain.d.ts +12 -0
- package/dist/execution/main/parseUint8ArrayStreamInMain.d.ts +12 -0
- package/dist/execution/wasm/parseBinaryInWASM.d.ts +18 -0
- package/dist/execution/wasm/parseBinaryInWASM.js +15 -0
- package/dist/execution/wasm/parseBinaryInWASM.js.map +1 -0
- package/dist/execution/wasm/parseStringInWASM.d.ts +16 -0
- package/dist/execution/worker/helpers/ReusableWorkerPool.d.ts +152 -0
- package/dist/execution/worker/helpers/ReusableWorkerPool.js +238 -0
- package/dist/execution/worker/helpers/ReusableWorkerPool.js.map +1 -0
- package/dist/execution/worker/helpers/TransientWorkerPool.d.ts +89 -0
- package/dist/execution/worker/helpers/WorkerManager.d.ts +27 -0
- package/dist/execution/worker/helpers/WorkerPool.d.ts +50 -0
- package/dist/execution/worker/helpers/WorkerSession.d.ts +78 -0
- package/dist/execution/worker/helpers/WorkerSession.js +58 -0
- package/dist/execution/worker/helpers/WorkerSession.js.map +1 -0
- package/dist/execution/worker/helpers/createWorker.node.d.ts +8 -0
- package/dist/execution/worker/helpers/createWorker.node.js +15 -0
- package/dist/execution/worker/helpers/createWorker.node.js.map +1 -0
- package/dist/execution/worker/helpers/createWorker.web.d.ts +8 -0
- package/dist/execution/worker/helpers/createWorker.web.js +11 -0
- package/dist/execution/worker/helpers/createWorker.web.js.map +1 -0
- package/dist/execution/worker/helpers/worker.node.d.ts +1 -0
- package/dist/execution/worker/helpers/worker.node.js +11 -0
- package/dist/execution/worker/helpers/worker.node.js.map +1 -0
- package/dist/execution/worker/helpers/worker.shared.d.ts +90 -0
- package/dist/execution/worker/helpers/worker.shared.js +241 -0
- package/dist/execution/worker/helpers/worker.shared.js.map +1 -0
- package/dist/execution/worker/helpers/worker.web.d.ts +1 -0
- package/dist/execution/worker/helpers/worker.web.js +16 -0
- package/dist/execution/worker/helpers/worker.web.js.map +1 -0
- package/dist/execution/worker/parseBinaryInWorker.node.d.ts +8 -0
- package/dist/execution/worker/parseBinaryInWorker.node.js +24 -0
- package/dist/execution/worker/parseBinaryInWorker.node.js.map +1 -0
- package/dist/execution/worker/parseBinaryInWorker.web.d.ts +8 -0
- package/dist/execution/worker/parseBinaryInWorker.web.js +24 -0
- package/dist/execution/worker/parseBinaryInWorker.web.js.map +1 -0
- package/dist/execution/worker/parseBinaryInWorkerWASM.node.d.ts +8 -0
- package/dist/execution/worker/parseBinaryInWorkerWASM.node.js +24 -0
- package/dist/execution/worker/parseBinaryInWorkerWASM.node.js.map +1 -0
- package/dist/execution/worker/parseBinaryInWorkerWASM.web.d.ts +8 -0
- package/dist/execution/worker/parseBinaryInWorkerWASM.web.js +24 -0
- package/dist/execution/worker/parseBinaryInWorkerWASM.web.js.map +1 -0
- package/dist/execution/worker/parseStreamInWorker.node.d.ts +15 -0
- package/dist/execution/worker/parseStreamInWorker.node.js +26 -0
- package/dist/execution/worker/parseStreamInWorker.node.js.map +1 -0
- package/dist/execution/worker/parseStreamInWorker.web.d.ts +12 -0
- package/dist/execution/worker/parseStreamInWorker.web.js +25 -0
- package/dist/execution/worker/parseStreamInWorker.web.js.map +1 -0
- package/dist/execution/worker/parseStringInWorker.node.d.ts +11 -0
- package/dist/execution/worker/parseStringInWorker.node.js +24 -0
- package/dist/execution/worker/parseStringInWorker.node.js.map +1 -0
- package/dist/execution/worker/parseStringInWorker.web.d.ts +11 -0
- package/dist/execution/worker/parseStringInWorker.web.js +24 -0
- package/dist/execution/worker/parseStringInWorker.web.js.map +1 -0
- package/dist/execution/worker/parseStringInWorkerWASM.node.d.ts +8 -0
- package/dist/execution/worker/parseStringInWorkerWASM.node.js +24 -0
- package/dist/execution/worker/parseStringInWorkerWASM.node.js.map +1 -0
- package/dist/execution/worker/parseStringInWorkerWASM.web.d.ts +8 -0
- package/dist/execution/worker/parseStringInWorkerWASM.web.js +24 -0
- package/dist/execution/worker/parseStringInWorkerWASM.web.js.map +1 -0
- package/dist/execution/worker/parseUint8ArrayStreamInWorker.node.d.ts +12 -0
- package/dist/execution/worker/parseUint8ArrayStreamInWorker.node.js +26 -0
- package/dist/execution/worker/parseUint8ArrayStreamInWorker.node.js.map +1 -0
- package/dist/execution/worker/parseUint8ArrayStreamInWorker.web.d.ts +9 -0
- package/dist/execution/worker/parseUint8ArrayStreamInWorker.web.js +25 -0
- package/dist/execution/worker/parseUint8ArrayStreamInWorker.web.js.map +1 -0
- package/dist/execution/worker/strategies/MessageStreamingStrategy.d.ts +17 -0
- package/dist/execution/worker/strategies/MessageStreamingStrategy.js +58 -0
- package/dist/execution/worker/strategies/MessageStreamingStrategy.js.map +1 -0
- package/dist/execution/worker/strategies/TransferableStreamStrategy.d.ts +25 -0
- package/dist/execution/worker/strategies/TransferableStreamStrategy.js +159 -0
- package/dist/execution/worker/strategies/TransferableStreamStrategy.js.map +1 -0
- package/dist/execution/worker/strategies/WorkerStrategy.d.ts +27 -0
- package/dist/execution/worker/strategies/WorkerStrategySelector.d.ts +43 -0
- package/dist/execution/worker/strategies/WorkerStrategySelector.js +89 -0
- package/dist/execution/worker/strategies/WorkerStrategySelector.js.map +1 -0
- package/dist/execution/worker/utils/messageHandler.d.ts +21 -0
- package/dist/execution/worker/utils/messageHandler.js +109 -0
- package/dist/execution/worker/utils/messageHandler.js.map +1 -0
- package/dist/execution/worker/utils/serializeOptions.d.ts +9 -0
- package/dist/execution/worker/utils/serializeOptions.js +14 -0
- package/dist/execution/worker/utils/serializeOptions.js.map +1 -0
- package/dist/execution/worker/utils/streamCollector.node.d.ts +14 -0
- package/dist/execution/worker/utils/streamCollector.node.js +78 -0
- package/dist/execution/worker/utils/streamCollector.node.js.map +1 -0
- package/dist/execution/worker/utils/workerUtils.d.ts +14 -0
- package/dist/execution/worker/utils/workerUtils.js +25 -0
- package/dist/execution/worker/utils/workerUtils.js.map +1 -0
- package/dist/getOptionsFromResponse.constants.node.d.ts +10 -0
- package/dist/getOptionsFromResponse.constants.node.js +8 -0
- package/dist/getOptionsFromResponse.constants.node.js.map +1 -0
- package/dist/getOptionsFromResponse.constants.web.d.ts +30 -0
- package/dist/getOptionsFromResponse.constants.web.js +7 -0
- package/dist/getOptionsFromResponse.constants.web.js.map +1 -0
- package/dist/getOptionsFromResponse.d.ts +2 -1
- package/dist/getOptionsFromResponse.js +5 -9
- package/dist/getOptionsFromResponse.js.map +1 -1
- package/dist/loadWASM.js.map +1 -1
- package/dist/loadWASM.web.js.map +1 -1
- package/dist/parse.d.ts +1 -1
- package/dist/parse.js +29 -5
- package/dist/parse.js.map +1 -1
- package/dist/parseBinary.d.ts +2 -1
- package/dist/parseBinary.js +32 -3
- package/dist/parseBinary.js.map +1 -1
- package/dist/parseBinaryInWorker.node.d.ts +2 -0
- package/dist/parseBinaryInWorker.web.d.ts +2 -0
- package/dist/parseBinaryInWorkerWASM.node.d.ts +2 -0
- package/dist/parseBinaryInWorkerWASM.web.d.ts +2 -0
- package/dist/parseBinaryToArraySync.d.ts +2 -1
- package/dist/parseBinaryToArraySync.js.map +1 -1
- package/dist/parseBinaryToIterableIterator.d.ts +2 -1
- package/dist/parseBinaryToIterableIterator.js.map +1 -1
- package/dist/parseBinaryToStream.d.ts +2 -1
- package/dist/parseBinaryToStream.js.map +1 -1
- package/dist/parseResponse.d.ts +1 -1
- package/dist/parseResponse.js +15 -8
- package/dist/parseResponse.js.map +1 -1
- package/dist/parseResponseToStream.d.ts +2 -1
- package/dist/parseResponseToStream.js.map +1 -1
- package/dist/parseStreamInWorker.node.d.ts +2 -0
- package/dist/parseStreamInWorker.web.d.ts +2 -0
- package/dist/parseString.d.ts +31 -0
- package/dist/parseString.js +27 -1
- package/dist/parseString.js.map +1 -1
- package/dist/parseStringInWorker.node.d.ts +2 -0
- package/dist/parseStringInWorker.web.d.ts +2 -0
- package/dist/parseStringInWorkerWASM.node.d.ts +2 -0
- package/dist/parseStringInWorkerWASM.web.d.ts +2 -0
- package/dist/parseStringStream.d.ts +43 -1
- package/dist/parseStringStream.js +24 -3
- package/dist/parseStringStream.js.map +1 -1
- package/dist/parseStringStreamToStream.js.map +1 -1
- package/dist/parseStringToArraySync.js.map +1 -1
- package/dist/parseStringToArraySyncWASM.js.map +1 -1
- package/dist/parseStringToIterableIterator.js.map +1 -1
- package/dist/parseStringToStream.js.map +1 -1
- package/dist/parseUint8ArrayStream.d.ts +4 -3
- package/dist/parseUint8ArrayStream.js +24 -3
- package/dist/parseUint8ArrayStream.js.map +1 -1
- package/dist/parseUint8ArrayStreamInWorker.node.d.ts +2 -0
- package/dist/parseUint8ArrayStreamInWorker.web.d.ts +2 -0
- package/dist/parseUint8ArrayStreamToStream.d.ts +2 -1
- package/dist/parseUint8ArrayStreamToStream.js +11 -5
- package/dist/parseUint8ArrayStreamToStream.js.map +1 -1
- package/dist/utils/convertBinaryToString.js.map +1 -1
- package/dist/utils/convertIterableIteratorToAsync.js.map +1 -1
- package/dist/utils/convertStreamToAsyncIterableIterator.js +2 -2
- package/dist/utils/convertStreamToAsyncIterableIterator.js.map +1 -1
- package/dist/utils/convertThisAsyncIterableIteratorToArray.d.ts +1 -1
- package/dist/utils/convertThisAsyncIterableIteratorToArray.js.map +1 -1
- package/dist/utils/escapeRegExp.js.map +1 -1
- package/dist/utils/parseMime.js.map +1 -1
- package/dist/utils/pipeline.js.map +1 -1
- package/dist/web-csv-toolbox.d.ts +4 -0
- package/dist/web-csv-toolbox.js +3 -0
- package/dist/web-csv-toolbox.js.map +1 -1
- package/dist/web_csv_toolbox_wasm_bg.wasm +0 -0
- package/dist/worker.node.d.ts +1 -0
- package/dist/worker.web.d.ts +1 -0
- package/package.json +53 -10
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import { createWorker } from './createWorker.web.js';
|
|
2
|
+
|
|
3
|
+
class ReusableWorkerPool {
|
|
4
|
+
workers = [];
|
|
5
|
+
requestId = 0;
|
|
6
|
+
currentWorkerIndex = 0;
|
|
7
|
+
maxWorkers;
|
|
8
|
+
customWorkerURL;
|
|
9
|
+
pendingWorkerCreations = /* @__PURE__ */ new Map();
|
|
10
|
+
pendingCreationsByURL = /* @__PURE__ */ new Map();
|
|
11
|
+
disposed = false;
|
|
12
|
+
nextPendingId = 0;
|
|
13
|
+
/**
|
|
14
|
+
* Create a new ReusableWorkerPool.
|
|
15
|
+
*
|
|
16
|
+
* @param options - Configuration options for the pool
|
|
17
|
+
*/
|
|
18
|
+
constructor(options = {}) {
|
|
19
|
+
this.maxWorkers = options.maxWorkers ?? 1;
|
|
20
|
+
this.customWorkerURL = options.workerURL;
|
|
21
|
+
if (this.maxWorkers < 1) {
|
|
22
|
+
throw new Error("maxWorkers must be at least 1");
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Get a worker instance from the pool using round-robin load balancing.
|
|
27
|
+
*
|
|
28
|
+
* @param workerURL - Optional custom worker URL (overrides pool's workerURL)
|
|
29
|
+
* @returns A worker instance from the pool
|
|
30
|
+
* @internal
|
|
31
|
+
*/
|
|
32
|
+
async getWorker(workerURL) {
|
|
33
|
+
if (this.disposed) {
|
|
34
|
+
throw new Error("Worker pool has been disposed");
|
|
35
|
+
}
|
|
36
|
+
const effectiveURL = workerURL ?? this.customWorkerURL;
|
|
37
|
+
const urlKey = effectiveURL ? String(effectiveURL) : "default";
|
|
38
|
+
const matchingWorkers = this.workers.filter(
|
|
39
|
+
(entry) => entry.url === urlKey
|
|
40
|
+
);
|
|
41
|
+
const totalWorkers = this.workers.length + this.pendingWorkerCreations.size;
|
|
42
|
+
if (totalWorkers < this.maxWorkers) {
|
|
43
|
+
const pendingId = `${urlKey}-${this.nextPendingId++}`;
|
|
44
|
+
const workerPromise = createWorker(effectiveURL).then((worker) => {
|
|
45
|
+
if (this.disposed) {
|
|
46
|
+
worker.terminate();
|
|
47
|
+
throw new Error("Worker pool was disposed during worker creation");
|
|
48
|
+
}
|
|
49
|
+
this.workers.push({ worker, url: urlKey });
|
|
50
|
+
this.pendingWorkerCreations.delete(pendingId);
|
|
51
|
+
const urlPendings2 = this.pendingCreationsByURL.get(urlKey);
|
|
52
|
+
if (urlPendings2) {
|
|
53
|
+
urlPendings2.delete(pendingId);
|
|
54
|
+
if (urlPendings2.size === 0) {
|
|
55
|
+
this.pendingCreationsByURL.delete(urlKey);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return worker;
|
|
59
|
+
}).catch((error) => {
|
|
60
|
+
this.pendingWorkerCreations.delete(pendingId);
|
|
61
|
+
const urlPendings2 = this.pendingCreationsByURL.get(urlKey);
|
|
62
|
+
if (urlPendings2) {
|
|
63
|
+
urlPendings2.delete(pendingId);
|
|
64
|
+
if (urlPendings2.size === 0) {
|
|
65
|
+
this.pendingCreationsByURL.delete(urlKey);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
throw error;
|
|
69
|
+
});
|
|
70
|
+
this.pendingWorkerCreations.set(pendingId, workerPromise);
|
|
71
|
+
if (!this.pendingCreationsByURL.has(urlKey)) {
|
|
72
|
+
this.pendingCreationsByURL.set(urlKey, /* @__PURE__ */ new Set());
|
|
73
|
+
}
|
|
74
|
+
this.pendingCreationsByURL.get(urlKey).add(pendingId);
|
|
75
|
+
return workerPromise;
|
|
76
|
+
}
|
|
77
|
+
if (matchingWorkers.length === 0) {
|
|
78
|
+
const urlPendings2 = this.pendingCreationsByURL.get(urlKey);
|
|
79
|
+
if (urlPendings2 && urlPendings2.size > 0) {
|
|
80
|
+
const pendingId = Array.from(urlPendings2)[0];
|
|
81
|
+
const pendingWorker = this.pendingWorkerCreations.get(pendingId);
|
|
82
|
+
if (pendingWorker) {
|
|
83
|
+
return pendingWorker;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
throw new Error(
|
|
87
|
+
`Worker pool is at maximum capacity (${this.maxWorkers}) and no worker with URL "${urlKey}" is available`
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
const urlPendings = this.pendingCreationsByURL.get(urlKey);
|
|
91
|
+
if (urlPendings && urlPendings.size > 0) {
|
|
92
|
+
const pendingId = Array.from(urlPendings)[0];
|
|
93
|
+
const pendingWorker = this.pendingWorkerCreations.get(pendingId);
|
|
94
|
+
if (pendingWorker) {
|
|
95
|
+
await pendingWorker;
|
|
96
|
+
const updatedMatchingWorkers = this.workers.filter(
|
|
97
|
+
(entry) => entry.url === urlKey
|
|
98
|
+
);
|
|
99
|
+
if (updatedMatchingWorkers.length === 0) {
|
|
100
|
+
throw new Error(
|
|
101
|
+
`Worker pool was disposed or worker creation failed for URL "${urlKey}"`
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
const matchingIndices = this.workers.map((entry, index) => entry.url === urlKey ? index : -1).filter((index) => index !== -1);
|
|
107
|
+
let selectedIndex = matchingIndices[0];
|
|
108
|
+
for (const index of matchingIndices) {
|
|
109
|
+
if (index >= this.currentWorkerIndex) {
|
|
110
|
+
selectedIndex = index;
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
this.currentWorkerIndex = (selectedIndex + 1) % this.workers.length;
|
|
115
|
+
return this.workers[selectedIndex].worker;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Get the next request ID for this pool.
|
|
119
|
+
*
|
|
120
|
+
* @returns The next request ID
|
|
121
|
+
* @internal
|
|
122
|
+
*/
|
|
123
|
+
getNextRequestId() {
|
|
124
|
+
return this.requestId++;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Release a worker back to the pool.
|
|
128
|
+
* For ReusableWorkerPool, this does nothing as workers are kept alive and reused.
|
|
129
|
+
*
|
|
130
|
+
* @param _worker - The worker to release
|
|
131
|
+
* @internal
|
|
132
|
+
*/
|
|
133
|
+
releaseWorker(_worker) {
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Get the current number of workers in the pool.
|
|
137
|
+
*
|
|
138
|
+
* @returns The number of active workers
|
|
139
|
+
*/
|
|
140
|
+
get size() {
|
|
141
|
+
return this.workers.length;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Check if the pool has reached its maximum capacity.
|
|
145
|
+
*
|
|
146
|
+
* @returns True if the pool is at maximum capacity, false otherwise
|
|
147
|
+
*
|
|
148
|
+
* @remarks
|
|
149
|
+
* This method is useful for implementing early rejection of requests
|
|
150
|
+
* when the worker pool is saturated, preventing resource exhaustion.
|
|
151
|
+
*
|
|
152
|
+
* @example
|
|
153
|
+
* ```ts
|
|
154
|
+
* import { Hono } from 'hono';
|
|
155
|
+
* import { ReusableWorkerPool } from 'web-csv-toolbox';
|
|
156
|
+
*
|
|
157
|
+
* const pool = new ReusableWorkerPool({ maxWorkers: 4 });
|
|
158
|
+
*
|
|
159
|
+
* app.post('/validate-csv', async (c) => {
|
|
160
|
+
* // Early rejection if pool is saturated
|
|
161
|
+
* if (pool.isFull()) {
|
|
162
|
+
* return c.json({ error: 'Service busy, please try again later' }, 503);
|
|
163
|
+
* }
|
|
164
|
+
*
|
|
165
|
+
* // Process CSV...
|
|
166
|
+
* });
|
|
167
|
+
* ```
|
|
168
|
+
*/
|
|
169
|
+
isFull() {
|
|
170
|
+
const totalWorkers = this.workers.length + this.pendingWorkerCreations.size;
|
|
171
|
+
return totalWorkers >= this.maxWorkers;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Terminate all workers in the pool and clean up resources.
|
|
175
|
+
*
|
|
176
|
+
* This method should be called when the pool is no longer needed,
|
|
177
|
+
* typically during application shutdown.
|
|
178
|
+
*
|
|
179
|
+
* @example
|
|
180
|
+
* ```ts
|
|
181
|
+
* const pool = new ReusableWorkerPool({ maxWorkers: 4 });
|
|
182
|
+
*
|
|
183
|
+
* // When shutting down
|
|
184
|
+
* pool.terminate();
|
|
185
|
+
* ```
|
|
186
|
+
*
|
|
187
|
+
* @example With Hono
|
|
188
|
+
* ```ts
|
|
189
|
+
* import { Hono } from 'hono';
|
|
190
|
+
* import { ReusableWorkerPool } from 'web-csv-toolbox';
|
|
191
|
+
*
|
|
192
|
+
* const app = new Hono();
|
|
193
|
+
* const pool = new ReusableWorkerPool({ maxWorkers: 4 });
|
|
194
|
+
*
|
|
195
|
+
* app.onShutdown(() => {
|
|
196
|
+
* pool.terminate();
|
|
197
|
+
* });
|
|
198
|
+
* ```
|
|
199
|
+
*/
|
|
200
|
+
terminate() {
|
|
201
|
+
this.disposed = true;
|
|
202
|
+
for (const entry of this.workers) {
|
|
203
|
+
entry.worker.terminate();
|
|
204
|
+
}
|
|
205
|
+
this.workers = [];
|
|
206
|
+
this.currentWorkerIndex = 0;
|
|
207
|
+
this.pendingWorkerCreations.clear();
|
|
208
|
+
this.pendingCreationsByURL.clear();
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Dispose of the worker pool, terminating all workers.
|
|
212
|
+
*
|
|
213
|
+
* This method is called automatically when using the `using` syntax.
|
|
214
|
+
* For manual cleanup, use {@link terminate} instead.
|
|
215
|
+
*
|
|
216
|
+
* @example With `using` syntax (automatic cleanup)
|
|
217
|
+
* ```ts
|
|
218
|
+
* using pool = new ReusableWorkerPool({ maxWorkers: 4 });
|
|
219
|
+
* // Workers are automatically terminated when leaving scope
|
|
220
|
+
* ```
|
|
221
|
+
*
|
|
222
|
+
* @example Manual cleanup
|
|
223
|
+
* ```ts
|
|
224
|
+
* const pool = new ReusableWorkerPool({ maxWorkers: 4 });
|
|
225
|
+
* try {
|
|
226
|
+
* // Use pool
|
|
227
|
+
* } finally {
|
|
228
|
+
* pool.terminate(); // Preferred over pool[Symbol.dispose]()
|
|
229
|
+
* }
|
|
230
|
+
* ```
|
|
231
|
+
*/
|
|
232
|
+
[Symbol.dispose]() {
|
|
233
|
+
this.terminate();
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
export { ReusableWorkerPool };
|
|
238
|
+
//# sourceMappingURL=ReusableWorkerPool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ReusableWorkerPool.js","sources":["../../../../src/execution/worker/helpers/ReusableWorkerPool.ts"],"sourcesContent":["import { createWorker } from \"#execution/worker/createWorker.js\";\nimport type { WorkerPool } from \"./WorkerPool.ts\";\n\n/**\n * Options for configuring the ReusableWorkerPool.\n */\nexport interface ReusableWorkerPoolOptions {\n /**\n * Maximum number of worker instances in the pool.\n *\n * @default 1\n *\n * @remarks\n * **Security Recommendation:**\n * For production applications that accept user uploads, set this to a reasonable limit (e.g., 2-4)\n * to prevent resource exhaustion attacks. Without limits, malicious users could spawn unlimited\n * workers by uploading multiple large CSV files simultaneously, leading to memory exhaustion and DoS.\n *\n * @example\n * ```ts\n * // Recommended for production\n * const pool = new ReusableReusableWorkerPool({ maxWorkers: 4 });\n * ```\n */\n maxWorkers?: number;\n\n /**\n * Custom worker URL to use for all workers in the pool.\n */\n workerURL?: string | URL;\n}\n\n/**\n * A pool that manages multiple worker instances with automatic cleanup and load balancing.\n *\n * This class implements the Disposable interface, allowing automatic\n * worker termination when the pool goes out of scope using the `using` syntax.\n *\n * @remarks\n * **⚠️ Security: Resource Protection**\n *\n * When building applications that accept user-uploaded CSV files, it is **strongly recommended**\n * to use `ReusableWorkerPool` with a limited `maxWorkers` setting to protect against resource exhaustion attacks.\n *\n * **Why this matters:**\n * - Attackers can upload multiple large CSV files simultaneously to overwhelm your application\n * - Without `ReusableWorkerPool` limits, each request could spawn unlimited workers\n * - This leads to excessive memory consumption, CPU exhaustion, and potential DoS\n *\n * **Recommended settings:**\n * - Web applications: `maxWorkers: 2-4`\n * - Server applications: `Math.min(4, os.cpus().length)`\n * - High-security environments: `maxWorkers: 1`\n *\n * See {@link https://github.com/kamiazya/web-csv-toolbox/blob/main/SECURITY.md | SECURITY.md} for detailed security guidelines.\n *\n * @example Basic usage with automatic cleanup (single worker)\n * ```ts\n * import { ReusableWorkerPool, parseString } from 'web-csv-toolbox';\n *\n * async function processCSV(csv: string) {\n * using pool = new ReusableWorkerPool();\n *\n * const records = [];\n * for await (const record of parseString(csv, {\n * execution: ['worker'],\n * workerPool: pool\n * })) {\n * records.push(record);\n * }\n *\n * return records;\n * // Worker is automatically terminated when leaving this scope\n * }\n * ```\n *\n * @example Parallel processing with multiple workers\n * ```ts\n * import { ReusableWorkerPool, parseString } from 'web-csv-toolbox';\n *\n * async function processMultipleCSVs(csvFiles: string[]) {\n * using pool = new ReusableWorkerPool({ maxWorkers: 4 });\n *\n * // Process all CSV files in parallel\n * const results = await Promise.all(\n * csvFiles.map(async (csv) => {\n * const records = [];\n * for await (const record of parseString(csv, {\n * execution: ['worker'],\n * workerPool: pool\n * })) {\n * records.push(record);\n * }\n * return records;\n * })\n * );\n *\n * return results;\n * // All workers are automatically terminated when leaving this scope\n * }\n * ```\n *\n * @example Manual cleanup (if not using `using` syntax)\n * ```ts\n * import { ReusableWorkerPool, parseString } from 'web-csv-toolbox';\n *\n * async function processCSV(csv: string) {\n * const pool = new ReusableWorkerPool({ maxWorkers: 2 });\n *\n * try {\n * const records = [];\n * for await (const record of parseString(csv, {\n * execution: ['worker'],\n * workerPool: pool\n * })) {\n * records.push(record);\n * }\n * return records;\n * } finally {\n * pool[Symbol.dispose]();\n * }\n * }\n * ```\n */\ninterface WorkerEntry {\n worker: Worker;\n url: string;\n}\n\nexport class ReusableWorkerPool implements WorkerPool, Disposable {\n private workers: WorkerEntry[] = [];\n private requestId = 0;\n private currentWorkerIndex = 0;\n private readonly maxWorkers: number;\n private readonly customWorkerURL?: string | URL;\n private pendingWorkerCreations: Map<string, Promise<Worker>> = new Map();\n private pendingCreationsByURL: Map<string, Set<string>> = new Map();\n private disposed = false;\n private nextPendingId = 0;\n\n /**\n * Create a new ReusableWorkerPool.\n *\n * @param options - Configuration options for the pool\n */\n constructor(options: ReusableWorkerPoolOptions = {}) {\n this.maxWorkers = options.maxWorkers ?? 1;\n this.customWorkerURL = options.workerURL;\n\n if (this.maxWorkers < 1) {\n throw new Error(\"maxWorkers must be at least 1\");\n }\n }\n\n /**\n * Get a worker instance from the pool using round-robin load balancing.\n *\n * @param workerURL - Optional custom worker URL (overrides pool's workerURL)\n * @returns A worker instance from the pool\n * @internal\n */\n async getWorker(workerURL?: string | URL): Promise<Worker> {\n if (this.disposed) {\n throw new Error(\"Worker pool has been disposed\");\n }\n\n const effectiveURL = workerURL ?? this.customWorkerURL;\n const urlKey = effectiveURL ? String(effectiveURL) : \"default\";\n\n // Find workers that match the requested URL\n const matchingWorkers = this.workers.filter(\n (entry) => entry.url === urlKey,\n );\n\n // Calculate total workers including pending creations\n const totalWorkers = this.workers.length + this.pendingWorkerCreations.size;\n\n // If pool is not yet full, create a new worker\n if (totalWorkers < this.maxWorkers) {\n // Generate unique key for this pending creation\n const pendingId = `${urlKey}-${this.nextPendingId++}`;\n\n // Create a new worker and cache the promise\n const workerPromise = createWorker(effectiveURL)\n .then((worker) => {\n if (this.disposed) {\n // If disposed during creation, terminate the new worker immediately\n worker.terminate();\n throw new Error(\"Worker pool was disposed during worker creation\");\n }\n this.workers.push({ worker, url: urlKey });\n this.pendingWorkerCreations.delete(pendingId);\n // Remove from URL-based tracking\n const urlPendings = this.pendingCreationsByURL.get(urlKey);\n if (urlPendings) {\n urlPendings.delete(pendingId);\n if (urlPendings.size === 0) {\n this.pendingCreationsByURL.delete(urlKey);\n }\n }\n return worker;\n })\n .catch((error) => {\n // Clean up on error\n this.pendingWorkerCreations.delete(pendingId);\n const urlPendings = this.pendingCreationsByURL.get(urlKey);\n if (urlPendings) {\n urlPendings.delete(pendingId);\n if (urlPendings.size === 0) {\n this.pendingCreationsByURL.delete(urlKey);\n }\n }\n throw error;\n });\n\n this.pendingWorkerCreations.set(pendingId, workerPromise);\n // Track by URL for future matching\n if (!this.pendingCreationsByURL.has(urlKey)) {\n this.pendingCreationsByURL.set(urlKey, new Set());\n }\n this.pendingCreationsByURL.get(urlKey)!.add(pendingId);\n\n return workerPromise;\n }\n\n // If pool is full and no matching workers exist, check for pending workers with this URL\n if (matchingWorkers.length === 0) {\n const urlPendings = this.pendingCreationsByURL.get(urlKey);\n if (urlPendings && urlPendings.size > 0) {\n // Wait for one of the pending workers with this URL\n const pendingId = Array.from(urlPendings)[0];\n const pendingWorker = this.pendingWorkerCreations.get(pendingId);\n if (pendingWorker) {\n return pendingWorker;\n }\n }\n\n throw new Error(\n `Worker pool is at maximum capacity (${this.maxWorkers}) and no worker with URL \"${urlKey}\" is available`,\n );\n }\n\n // Wait for any pending worker creations with this URL to complete\n const urlPendings = this.pendingCreationsByURL.get(urlKey);\n if (urlPendings && urlPendings.size > 0) {\n const pendingId = Array.from(urlPendings)[0];\n const pendingWorker = this.pendingWorkerCreations.get(pendingId);\n if (pendingWorker) {\n await pendingWorker;\n // Re-fetch matching workers as the pending creation may have completed\n const updatedMatchingWorkers = this.workers.filter(\n (entry) => entry.url === urlKey,\n );\n if (updatedMatchingWorkers.length === 0) {\n throw new Error(\n `Worker pool was disposed or worker creation failed for URL \"${urlKey}\"`,\n );\n }\n }\n }\n\n // Use round-robin among matching workers\n const matchingIndices = this.workers\n .map((entry, index) => (entry.url === urlKey ? index : -1))\n .filter((index) => index !== -1);\n\n // Find next matching worker in round-robin order\n let selectedIndex = matchingIndices[0];\n for (const index of matchingIndices) {\n if (index >= this.currentWorkerIndex) {\n selectedIndex = index;\n break;\n }\n }\n\n this.currentWorkerIndex = (selectedIndex + 1) % this.workers.length;\n return this.workers[selectedIndex].worker;\n }\n\n /**\n * Get the next request ID for this pool.\n *\n * @returns The next request ID\n * @internal\n */\n getNextRequestId(): number {\n return this.requestId++;\n }\n\n /**\n * Release a worker back to the pool.\n * For ReusableWorkerPool, this does nothing as workers are kept alive and reused.\n *\n * @param _worker - The worker to release\n * @internal\n */\n releaseWorker(_worker: Worker): void {\n // ReusableWorkerPool keeps workers alive for reuse\n }\n\n /**\n * Get the current number of workers in the pool.\n *\n * @returns The number of active workers\n */\n get size(): number {\n return this.workers.length;\n }\n\n /**\n * Check if the pool has reached its maximum capacity.\n *\n * @returns True if the pool is at maximum capacity, false otherwise\n *\n * @remarks\n * This method is useful for implementing early rejection of requests\n * when the worker pool is saturated, preventing resource exhaustion.\n *\n * @example\n * ```ts\n * import { Hono } from 'hono';\n * import { ReusableWorkerPool } from 'web-csv-toolbox';\n *\n * const pool = new ReusableWorkerPool({ maxWorkers: 4 });\n *\n * app.post('/validate-csv', async (c) => {\n * // Early rejection if pool is saturated\n * if (pool.isFull()) {\n * return c.json({ error: 'Service busy, please try again later' }, 503);\n * }\n *\n * // Process CSV...\n * });\n * ```\n */\n isFull(): boolean {\n const totalWorkers = this.workers.length + this.pendingWorkerCreations.size;\n return totalWorkers >= this.maxWorkers;\n }\n\n /**\n * Terminate all workers in the pool and clean up resources.\n *\n * This method should be called when the pool is no longer needed,\n * typically during application shutdown.\n *\n * @example\n * ```ts\n * const pool = new ReusableWorkerPool({ maxWorkers: 4 });\n *\n * // When shutting down\n * pool.terminate();\n * ```\n *\n * @example With Hono\n * ```ts\n * import { Hono } from 'hono';\n * import { ReusableWorkerPool } from 'web-csv-toolbox';\n *\n * const app = new Hono();\n * const pool = new ReusableWorkerPool({ maxWorkers: 4 });\n *\n * app.onShutdown(() => {\n * pool.terminate();\n * });\n * ```\n */\n terminate(): void {\n this.disposed = true;\n\n // Terminate all existing workers\n for (const entry of this.workers) {\n entry.worker.terminate();\n }\n this.workers = [];\n this.currentWorkerIndex = 0;\n\n // Reject and clear all pending worker creations\n // Note: The pending promises will handle cleanup via their catch blocks\n this.pendingWorkerCreations.clear();\n this.pendingCreationsByURL.clear();\n }\n\n /**\n * Dispose of the worker pool, terminating all workers.\n *\n * This method is called automatically when using the `using` syntax.\n * For manual cleanup, use {@link terminate} instead.\n *\n * @example With `using` syntax (automatic cleanup)\n * ```ts\n * using pool = new ReusableWorkerPool({ maxWorkers: 4 });\n * // Workers are automatically terminated when leaving scope\n * ```\n *\n * @example Manual cleanup\n * ```ts\n * const pool = new ReusableWorkerPool({ maxWorkers: 4 });\n * try {\n * // Use pool\n * } finally {\n * pool.terminate(); // Preferred over pool[Symbol.dispose]()\n * }\n * ```\n */\n [Symbol.dispose](): void {\n this.terminate();\n }\n}\n"],"names":["urlPendings"],"mappings":"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"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { WorkerPool } from './WorkerPool.ts';
|
|
2
|
+
/**
|
|
3
|
+
* Options for configuring the TransientWorkerPool.
|
|
4
|
+
*/
|
|
5
|
+
export interface TransientWorkerPoolOptions {
|
|
6
|
+
/**
|
|
7
|
+
* Custom worker URL to use for all workers in the pool.
|
|
8
|
+
*/
|
|
9
|
+
workerURL?: string | URL;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* A pool that creates transient workers which are automatically terminated after each job.
|
|
13
|
+
*
|
|
14
|
+
* This pool is designed for the default worker pool to prevent workers from staying alive
|
|
15
|
+
* and blocking process exit. Each worker is terminated immediately after the job completes.
|
|
16
|
+
*
|
|
17
|
+
* @remarks
|
|
18
|
+
* **Design Rationale:**
|
|
19
|
+
*
|
|
20
|
+
* Unlike {@link ReusableWorkerPool} which keeps workers alive for reuse, `TransientWorkerPool`
|
|
21
|
+
* terminates workers after each job. This is specifically designed for the internal default pool
|
|
22
|
+
* to avoid requiring users to call `terminateWorkers()` for process cleanup.
|
|
23
|
+
*
|
|
24
|
+
* **Characteristics:**
|
|
25
|
+
* - Workers are created on-demand
|
|
26
|
+
* - Workers are terminated immediately after job completion
|
|
27
|
+
* - No persistent worker instances
|
|
28
|
+
* - Prevents process from hanging due to active workers
|
|
29
|
+
*
|
|
30
|
+
* @internal
|
|
31
|
+
*/
|
|
32
|
+
export declare class TransientWorkerPool implements WorkerPool, Disposable {
|
|
33
|
+
private requestId;
|
|
34
|
+
private readonly customWorkerURL?;
|
|
35
|
+
/**
|
|
36
|
+
* Create a new TransientWorkerPool.
|
|
37
|
+
*
|
|
38
|
+
* @param options - Configuration options for the pool
|
|
39
|
+
*/
|
|
40
|
+
constructor(options?: TransientWorkerPoolOptions);
|
|
41
|
+
/**
|
|
42
|
+
* Get a worker instance.
|
|
43
|
+
* Always creates a new worker for transient usage.
|
|
44
|
+
*
|
|
45
|
+
* @param workerURL - Optional custom worker URL (overrides pool's workerURL)
|
|
46
|
+
* @returns A new worker instance
|
|
47
|
+
* @internal
|
|
48
|
+
*/
|
|
49
|
+
getWorker(workerURL?: string | URL): Promise<Worker>;
|
|
50
|
+
/**
|
|
51
|
+
* Get the next request ID for this pool.
|
|
52
|
+
*
|
|
53
|
+
* @returns The next request ID
|
|
54
|
+
* @internal
|
|
55
|
+
*/
|
|
56
|
+
getNextRequestId(): number;
|
|
57
|
+
/**
|
|
58
|
+
* Release a worker back to the pool.
|
|
59
|
+
* For TransientWorkerPool, this terminates the worker immediately.
|
|
60
|
+
*
|
|
61
|
+
* @param worker - The worker to release
|
|
62
|
+
* @internal
|
|
63
|
+
*/
|
|
64
|
+
releaseWorker(worker: Worker): void;
|
|
65
|
+
/**
|
|
66
|
+
* Get the current number of workers in the pool.
|
|
67
|
+
* For TransientWorkerPool, this is always 0 as workers are not kept alive.
|
|
68
|
+
*
|
|
69
|
+
* @returns Always 0
|
|
70
|
+
*/
|
|
71
|
+
get size(): number;
|
|
72
|
+
/**
|
|
73
|
+
* Check if the pool has reached its maximum capacity.
|
|
74
|
+
* For TransientWorkerPool, this is always false as workers are transient.
|
|
75
|
+
*
|
|
76
|
+
* @returns Always false
|
|
77
|
+
*/
|
|
78
|
+
isFull(): boolean;
|
|
79
|
+
/**
|
|
80
|
+
* Terminate all workers in the pool.
|
|
81
|
+
* For TransientWorkerPool, this is a no-op as workers are not kept alive.
|
|
82
|
+
*/
|
|
83
|
+
terminate(): void;
|
|
84
|
+
/**
|
|
85
|
+
* Dispose of the worker pool.
|
|
86
|
+
* For TransientWorkerPool, this is a no-op as workers are not kept alive.
|
|
87
|
+
*/
|
|
88
|
+
[Symbol.dispose](): void;
|
|
89
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get or create a worker instance from the default pool.
|
|
3
|
+
* If WorkerPool is provided in options, use it instead of default pool.
|
|
4
|
+
*
|
|
5
|
+
* @internal
|
|
6
|
+
*/
|
|
7
|
+
export declare function getWorker(workerURL?: string | URL): Promise<Worker>;
|
|
8
|
+
/**
|
|
9
|
+
* Get next request ID for message tracking from the default pool.
|
|
10
|
+
*
|
|
11
|
+
* @internal
|
|
12
|
+
*/
|
|
13
|
+
export declare function getNextRequestId(): number;
|
|
14
|
+
/**
|
|
15
|
+
* Release a worker back to the default pool.
|
|
16
|
+
* For the default transient pool, this terminates the worker.
|
|
17
|
+
*
|
|
18
|
+
* @internal
|
|
19
|
+
*/
|
|
20
|
+
export declare function releaseWorker(worker: Worker): void;
|
|
21
|
+
/**
|
|
22
|
+
* Get the current size of the default pool.
|
|
23
|
+
* This is mainly for testing purposes.
|
|
24
|
+
*
|
|
25
|
+
* @internal
|
|
26
|
+
*/
|
|
27
|
+
export declare function getPoolSize(): number;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Common interface for worker pools.
|
|
3
|
+
* Both ReusableWorkerPool and TransientWorkerPool implement this interface.
|
|
4
|
+
*
|
|
5
|
+
* @remarks
|
|
6
|
+
* This interface defines the contract for worker pool implementations.
|
|
7
|
+
* Users typically use {@link ReusableWorkerPool} for persistent worker pools,
|
|
8
|
+
* while the internal default pool uses {@link TransientWorkerPool} for automatic cleanup.
|
|
9
|
+
*/
|
|
10
|
+
export interface WorkerPool {
|
|
11
|
+
/**
|
|
12
|
+
* Get a worker instance from the pool.
|
|
13
|
+
*
|
|
14
|
+
* @param workerURL - Optional custom worker URL
|
|
15
|
+
* @returns A worker instance
|
|
16
|
+
*/
|
|
17
|
+
getWorker(workerURL?: string | URL): Promise<Worker>;
|
|
18
|
+
/**
|
|
19
|
+
* Get the next request ID for this pool.
|
|
20
|
+
*
|
|
21
|
+
* @returns The next request ID
|
|
22
|
+
*/
|
|
23
|
+
getNextRequestId(): number;
|
|
24
|
+
/**
|
|
25
|
+
* Release a worker back to the pool.
|
|
26
|
+
*
|
|
27
|
+
* @param worker - The worker to release
|
|
28
|
+
*/
|
|
29
|
+
releaseWorker(worker: Worker): void;
|
|
30
|
+
/**
|
|
31
|
+
* Get the current number of workers in the pool.
|
|
32
|
+
*
|
|
33
|
+
* @returns The number of active workers
|
|
34
|
+
*/
|
|
35
|
+
readonly size: number;
|
|
36
|
+
/**
|
|
37
|
+
* Check if the pool has reached its maximum capacity.
|
|
38
|
+
*
|
|
39
|
+
* @returns True if the pool is at maximum capacity, false otherwise
|
|
40
|
+
*/
|
|
41
|
+
isFull(): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Terminate all workers in the pool and clean up resources.
|
|
44
|
+
*/
|
|
45
|
+
terminate(): void;
|
|
46
|
+
/**
|
|
47
|
+
* Dispose of the worker pool, terminating all workers.
|
|
48
|
+
*/
|
|
49
|
+
[Symbol.dispose](): void;
|
|
50
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { WorkerPool } from './WorkerPool.ts';
|
|
2
|
+
/**
|
|
3
|
+
* Options for creating a WorkerSession.
|
|
4
|
+
*/
|
|
5
|
+
export interface WorkerSessionOptions {
|
|
6
|
+
/**
|
|
7
|
+
* Custom worker URL.
|
|
8
|
+
*/
|
|
9
|
+
workerURL?: string | URL;
|
|
10
|
+
/**
|
|
11
|
+
* Worker pool for reusable workers.
|
|
12
|
+
*/
|
|
13
|
+
workerPool?: WorkerPool;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* WorkerSession manages the lifecycle of a single worker instance.
|
|
17
|
+
*
|
|
18
|
+
* Hybrid approach:
|
|
19
|
+
* - If workerPool is provided: Use pool's worker (reusable, manual pool cleanup)
|
|
20
|
+
* - If workerPool is NOT provided: Create disposable worker (auto-cleanup on dispose)
|
|
21
|
+
*
|
|
22
|
+
* Use `using` syntax for automatic cleanup:
|
|
23
|
+
* ```typescript
|
|
24
|
+
* using session = await WorkerSession.create();
|
|
25
|
+
* const records = await sendWorkerMessage(session, { ... });
|
|
26
|
+
* // Worker is automatically terminated when leaving scope (if disposable)
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* @example Disposable worker (one-time use)
|
|
30
|
+
* ```typescript
|
|
31
|
+
* using session = await WorkerSession.create();
|
|
32
|
+
* const records = await sendWorkerMessage(session.getWorker(), {
|
|
33
|
+
* id: session.getNextRequestId(),
|
|
34
|
+
* type: "parseString",
|
|
35
|
+
* data: csv,
|
|
36
|
+
* options: serializeOptions(options),
|
|
37
|
+
* });
|
|
38
|
+
* // Worker automatically terminated
|
|
39
|
+
* ```
|
|
40
|
+
*
|
|
41
|
+
* @example With WorkerPool (reusable)
|
|
42
|
+
* ```typescript
|
|
43
|
+
* using pool = new WorkerPool({ maxWorkers: 3 });
|
|
44
|
+
* using session = await WorkerSession.create({ workerPool: pool });
|
|
45
|
+
* const records1 = await sendWorkerMessage(session.getWorker(), { ... });
|
|
46
|
+
* const records2 = await sendWorkerMessage(session.getWorker(), { ... });
|
|
47
|
+
* // Worker returned to pool, pool cleanup happens when pool disposes
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export declare class WorkerSession implements Disposable {
|
|
51
|
+
private worker;
|
|
52
|
+
private requestIdCounter;
|
|
53
|
+
private readonly workerPool?;
|
|
54
|
+
private constructor();
|
|
55
|
+
/**
|
|
56
|
+
* Create a new WorkerSession.
|
|
57
|
+
*
|
|
58
|
+
* @param options Session options
|
|
59
|
+
* @returns Promise that resolves to a WorkerSession instance
|
|
60
|
+
*/
|
|
61
|
+
static create(options?: WorkerSessionOptions): Promise<WorkerSession>;
|
|
62
|
+
/**
|
|
63
|
+
* Get the worker instance.
|
|
64
|
+
*/
|
|
65
|
+
getWorker(): Worker;
|
|
66
|
+
/**
|
|
67
|
+
* Get the next request ID for this session.
|
|
68
|
+
* - If using WorkerPool: Delegates to pool's getNextRequestId()
|
|
69
|
+
* - If disposable: Uses internal counter
|
|
70
|
+
*/
|
|
71
|
+
getNextRequestId(): number;
|
|
72
|
+
/**
|
|
73
|
+
* Dispose the session.
|
|
74
|
+
* - If using a pool: Releases the worker back to the pool (behavior depends on pool type)
|
|
75
|
+
* - If disposable: Terminates the worker
|
|
76
|
+
*/
|
|
77
|
+
[Symbol.dispose](): void;
|
|
78
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { createWorker } from './createWorker.web.js';
|
|
2
|
+
|
|
3
|
+
class WorkerSession {
|
|
4
|
+
worker;
|
|
5
|
+
requestIdCounter = 0;
|
|
6
|
+
workerPool;
|
|
7
|
+
constructor(worker, workerPool) {
|
|
8
|
+
this.worker = worker;
|
|
9
|
+
this.workerPool = workerPool;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Create a new WorkerSession.
|
|
13
|
+
*
|
|
14
|
+
* @param options Session options
|
|
15
|
+
* @returns Promise that resolves to a WorkerSession instance
|
|
16
|
+
*/
|
|
17
|
+
static async create(options) {
|
|
18
|
+
let worker;
|
|
19
|
+
if (options?.workerPool) {
|
|
20
|
+
worker = await options.workerPool.getWorker(options.workerURL);
|
|
21
|
+
return new WorkerSession(worker, options.workerPool);
|
|
22
|
+
}
|
|
23
|
+
worker = await createWorker(options?.workerURL);
|
|
24
|
+
return new WorkerSession(worker);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Get the worker instance.
|
|
28
|
+
*/
|
|
29
|
+
getWorker() {
|
|
30
|
+
return this.worker;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Get the next request ID for this session.
|
|
34
|
+
* - If using WorkerPool: Delegates to pool's getNextRequestId()
|
|
35
|
+
* - If disposable: Uses internal counter
|
|
36
|
+
*/
|
|
37
|
+
getNextRequestId() {
|
|
38
|
+
if (this.workerPool) {
|
|
39
|
+
return this.workerPool.getNextRequestId();
|
|
40
|
+
}
|
|
41
|
+
return this.requestIdCounter++;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Dispose the session.
|
|
45
|
+
* - If using a pool: Releases the worker back to the pool (behavior depends on pool type)
|
|
46
|
+
* - If disposable: Terminates the worker
|
|
47
|
+
*/
|
|
48
|
+
[Symbol.dispose]() {
|
|
49
|
+
if (this.workerPool) {
|
|
50
|
+
this.workerPool.releaseWorker(this.worker);
|
|
51
|
+
} else {
|
|
52
|
+
this.worker.terminate();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export { WorkerSession };
|
|
58
|
+
//# sourceMappingURL=WorkerSession.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WorkerSession.js","sources":["../../../../src/execution/worker/helpers/WorkerSession.ts"],"sourcesContent":["import { createWorker } from \"#execution/worker/createWorker.js\";\nimport type { WorkerPool } from \"./WorkerPool.ts\";\n\n/**\n * Options for creating a WorkerSession.\n */\nexport interface WorkerSessionOptions {\n /**\n * Custom worker URL.\n */\n workerURL?: string | URL;\n\n /**\n * Worker pool for reusable workers.\n */\n workerPool?: WorkerPool;\n}\n\n/**\n * WorkerSession manages the lifecycle of a single worker instance.\n *\n * Hybrid approach:\n * - If workerPool is provided: Use pool's worker (reusable, manual pool cleanup)\n * - If workerPool is NOT provided: Create disposable worker (auto-cleanup on dispose)\n *\n * Use `using` syntax for automatic cleanup:\n * ```typescript\n * using session = await WorkerSession.create();\n * const records = await sendWorkerMessage(session, { ... });\n * // Worker is automatically terminated when leaving scope (if disposable)\n * ```\n *\n * @example Disposable worker (one-time use)\n * ```typescript\n * using session = await WorkerSession.create();\n * const records = await sendWorkerMessage(session.getWorker(), {\n * id: session.getNextRequestId(),\n * type: \"parseString\",\n * data: csv,\n * options: serializeOptions(options),\n * });\n * // Worker automatically terminated\n * ```\n *\n * @example With WorkerPool (reusable)\n * ```typescript\n * using pool = new WorkerPool({ maxWorkers: 3 });\n * using session = await WorkerSession.create({ workerPool: pool });\n * const records1 = await sendWorkerMessage(session.getWorker(), { ... });\n * const records2 = await sendWorkerMessage(session.getWorker(), { ... });\n * // Worker returned to pool, pool cleanup happens when pool disposes\n * ```\n */\nexport class WorkerSession implements Disposable {\n private worker: Worker;\n private requestIdCounter = 0;\n private readonly workerPool?: WorkerPool;\n\n private constructor(worker: Worker, workerPool?: WorkerPool) {\n this.worker = worker;\n this.workerPool = workerPool;\n }\n\n /**\n * Create a new WorkerSession.\n *\n * @param options Session options\n * @returns Promise that resolves to a WorkerSession instance\n */\n static async create(options?: WorkerSessionOptions): Promise<WorkerSession> {\n let worker: Worker;\n if (options?.workerPool) {\n // Use worker from pool\n worker = await options.workerPool.getWorker(options.workerURL);\n return new WorkerSession(worker, options.workerPool);\n }\n // Create disposable worker\n worker = await createWorker(options?.workerURL);\n return new WorkerSession(worker);\n }\n\n /**\n * Get the worker instance.\n */\n getWorker(): Worker {\n return this.worker;\n }\n\n /**\n * Get the next request ID for this session.\n * - If using WorkerPool: Delegates to pool's getNextRequestId()\n * - If disposable: Uses internal counter\n */\n getNextRequestId(): number {\n if (this.workerPool) {\n return this.workerPool.getNextRequestId();\n }\n return this.requestIdCounter++;\n }\n\n /**\n * Dispose the session.\n * - If using a pool: Releases the worker back to the pool (behavior depends on pool type)\n * - If disposable: Terminates the worker\n */\n [Symbol.dispose](): void {\n if (this.workerPool) {\n this.workerPool.releaseWorker(this.worker);\n } else {\n this.worker.terminate();\n }\n }\n}\n"],"names":[],"mappings":";;AAqDO,MAAM,aAAA,CAAoC;AAAA,EACvC,MAAA;AAAA,EACA,gBAAA,GAAmB,CAAA;AAAA,EACV,UAAA;AAAA,EAET,WAAA,CAAY,QAAgB,UAAA,EAAyB;AAC3D,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AACd,IAAA,IAAA,CAAK,UAAA,GAAa,UAAA;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,aAAa,OAAO,OAAA,EAAwD;AAC1E,IAAA,IAAI,MAAA;AACJ,IAAA,IAAI,SAAS,UAAA,EAAY;AAEvB,MAAA,MAAA,GAAS,MAAM,OAAA,CAAQ,UAAA,CAAW,SAAA,CAAU,QAAQ,SAAS,CAAA;AAC7D,MAAA,OAAO,IAAI,aAAA,CAAc,MAAA,EAAQ,OAAA,CAAQ,UAAU,CAAA;AAAA,IACrD;AAEA,IAAA,MAAA,GAAS,MAAM,YAAA,CAAa,OAAA,EAAS,SAAS,CAAA;AAC9C,IAAA,OAAO,IAAI,cAAc,MAAM,CAAA;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA,EAKA,SAAA,GAAoB;AAClB,IAAA,OAAO,IAAA,CAAK,MAAA;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,gBAAA,GAA2B;AACzB,IAAA,IAAI,KAAK,UAAA,EAAY;AACnB,MAAA,OAAO,IAAA,CAAK,WAAW,gBAAA,EAAiB;AAAA,IAC1C;AACA,IAAA,OAAO,IAAA,CAAK,gBAAA,EAAA;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,CAAC,MAAA,CAAO,OAAO,CAAA,GAAU;AACvB,IAAA,IAAI,KAAK,UAAA,EAAY;AACnB,MAAA,IAAA,CAAK,UAAA,CAAW,aAAA,CAAc,IAAA,CAAK,MAAM,CAAA;AAAA,IAC3C,CAAA,MAAO;AACL,MAAA,IAAA,CAAK,OAAO,SAAA,EAAU;AAAA,IACxB;AAAA,EACF;AACF;;;;"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Create a Worker instance for Node.js environment.
|
|
3
|
+
*
|
|
4
|
+
* @internal
|
|
5
|
+
* @param workerURL Custom worker URL or undefined to use bundled worker
|
|
6
|
+
* @returns Worker instance
|
|
7
|
+
*/
|
|
8
|
+
export declare function createWorker(workerURL?: string | URL): Promise<Worker>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
async function createWorker(workerURL) {
|
|
2
|
+
const { Worker } = await import('node:worker_threads');
|
|
3
|
+
const { fileURLToPath } = await import('node:url');
|
|
4
|
+
const { dirname, join } = await import('node:path');
|
|
5
|
+
if (workerURL) {
|
|
6
|
+
return new Worker(workerURL, { type: "module" });
|
|
7
|
+
}
|
|
8
|
+
const currentFilePath = fileURLToPath(import.meta.url);
|
|
9
|
+
const currentDir = dirname(currentFilePath);
|
|
10
|
+
const workerPath = join(currentDir, "worker.node.js");
|
|
11
|
+
return new Worker(workerPath, { type: "module" });
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export { createWorker };
|
|
15
|
+
//# sourceMappingURL=createWorker.node.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createWorker.node.js","sources":["../../../../src/execution/worker/helpers/createWorker.node.ts"],"sourcesContent":["/**\n * Create a Worker instance for Node.js environment.\n *\n * @internal\n * @param workerURL Custom worker URL or undefined to use bundled worker\n * @returns Worker instance\n */\nexport async function createWorker(workerURL?: string | URL): Promise<Worker> {\n // Dynamic import for Node.js Worker and URL utilities\n // @ts-ignore: node:worker_threads is only available in Node.js\n const { Worker } = await import(\"node:worker_threads\");\n // @ts-ignore: node:url is only available in Node.js\n const { fileURLToPath } = await import(\"node:url\");\n // @ts-ignore: node:path is only available in Node.js\n const { dirname, join } = await import(\"node:path\");\n\n if (workerURL) {\n // Use provided worker URL\n return new Worker(workerURL, { type: \"module\" });\n }\n\n // Compute worker.node.js path relative to this module\n // In Node.js, import.meta.url is a file:// URL pointing to this module\n const currentFilePath = fileURLToPath(import.meta.url);\n const currentDir = dirname(currentFilePath);\n const workerPath = join(currentDir, \"worker.node.js\");\n\n // @ts-ignore\n return new Worker(workerPath, { type: \"module\" });\n}\n"],"names":[],"mappings":"AAOA,eAAsB,aAAa,SAAA,EAA2C;AAG5E,EAAA,MAAM,EAAE,MAAA,EAAO,GAAI,MAAM,OAAO,qBAAqB,CAAA;AAErD,EAAA,MAAM,EAAE,aAAA,EAAc,GAAI,MAAM,OAAO,UAAU,CAAA;AAEjD,EAAA,MAAM,EAAE,OAAA,EAAS,IAAA,EAAK,GAAI,MAAM,OAAO,WAAW,CAAA;AAElD,EAAA,IAAI,SAAA,EAAW;AAEb,IAAA,OAAO,IAAI,MAAA,CAAO,SAAA,EAAW,EAAE,IAAA,EAAM,UAAU,CAAA;AAAA,EACjD;AAIA,EAAA,MAAM,eAAA,GAAkB,aAAA,CAAc,MAAA,CAAA,IAAA,CAAY,GAAG,CAAA;AACrD,EAAA,MAAM,UAAA,GAAa,QAAQ,eAAe,CAAA;AAC1C,EAAA,MAAM,UAAA,GAAa,IAAA,CAAK,UAAA,EAAY,gBAAgB,CAAA;AAGpD,EAAA,OAAO,IAAI,MAAA,CAAO,UAAA,EAAY,EAAE,IAAA,EAAM,UAAU,CAAA;AAClD;;;;"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Create a Worker instance for browser/Deno environment.
|
|
3
|
+
*
|
|
4
|
+
* @internal
|
|
5
|
+
* @param workerURL Custom worker URL or undefined to use bundled worker
|
|
6
|
+
* @returns Worker instance
|
|
7
|
+
*/
|
|
8
|
+
export declare function createWorker(workerURL?: string | URL): Promise<Worker>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
async function createWorker(workerURL) {
|
|
2
|
+
const url = workerURL || new URL(
|
|
3
|
+
/* @vite-ignore */
|
|
4
|
+
"./worker.web.js",
|
|
5
|
+
import.meta.url
|
|
6
|
+
);
|
|
7
|
+
return new Worker(url, { type: "module" });
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export { createWorker };
|
|
11
|
+
//# sourceMappingURL=createWorker.web.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createWorker.web.js","sources":["../../../../src/execution/worker/helpers/createWorker.web.ts"],"sourcesContent":["/**\n * Create a Worker instance for browser/Deno environment.\n *\n * @internal\n * @param workerURL Custom worker URL or undefined to use bundled worker\n * @returns Worker instance\n */\nexport async function createWorker(workerURL?: string | URL): Promise<Worker> {\n // Use @vite-ignore to prevent Vite from inlining the worker as a data URL\n // In production, import.meta.url points to dist/execution/worker/helpers/createWorker.web.js\n // so \"./worker.web.js\" correctly resolves to dist/execution/worker/helpers/worker.web.js\n const url =\n workerURL || new URL(/* @vite-ignore */ \"./worker.web.js\", import.meta.url);\n return new Worker(url, { type: \"module\" });\n}\n"],"names":[],"mappings":"AAOA,eAAsB,aAAa,SAAA,EAA2C;AAI5E,EAAA,MAAM,GAAA,GACJ,aAAa,IAAI,GAAA;AAAA;AAAA,IAAuB,iBAAA;AAAA,IAAmB,MAAA,CAAA,IAAA,CAAY;AAAA,GAAG;AAC5E,EAAA,OAAO,IAAI,MAAA,CAAO,GAAA,EAAK,EAAE,IAAA,EAAM,UAAU,CAAA;AAC3C;;;;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { parentPort } from 'node:worker_threads';
|
|
2
|
+
import { createMessageHandler } from './worker.shared.js';
|
|
3
|
+
|
|
4
|
+
if (!parentPort) {
|
|
5
|
+
throw new Error("This module must be run in a Worker Thread context");
|
|
6
|
+
}
|
|
7
|
+
const messageHandler = createMessageHandler(parentPort);
|
|
8
|
+
parentPort.on("message", (message) => {
|
|
9
|
+
messageHandler(message);
|
|
10
|
+
});
|
|
11
|
+
//# sourceMappingURL=worker.node.js.map
|