@dmop/puru 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +418 -0
- package/dist/index.cjs +1515 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +128 -0
- package/dist/index.d.ts +128 -0
- package/dist/index.js +1472 -0
- package/dist/index.js.map +1 -0
- package/package.json +73 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,1515 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
ErrGroup: () => ErrGroup,
|
|
24
|
+
Mutex: () => Mutex,
|
|
25
|
+
Once: () => Once,
|
|
26
|
+
Ticker: () => Ticker,
|
|
27
|
+
WaitGroup: () => WaitGroup,
|
|
28
|
+
after: () => after,
|
|
29
|
+
chan: () => chan,
|
|
30
|
+
configure: () => configure,
|
|
31
|
+
detectCapability: () => detectCapability,
|
|
32
|
+
detectRuntime: () => detectRuntime,
|
|
33
|
+
register: () => register,
|
|
34
|
+
resize: () => resize,
|
|
35
|
+
run: () => run,
|
|
36
|
+
select: () => select,
|
|
37
|
+
spawn: () => spawn,
|
|
38
|
+
stats: () => stats,
|
|
39
|
+
ticker: () => ticker
|
|
40
|
+
});
|
|
41
|
+
module.exports = __toCommonJS(index_exports);
|
|
42
|
+
|
|
43
|
+
// src/serialize.ts
|
|
44
|
+
var NATIVE_CODE_RE = /\[native code\]/;
|
|
45
|
+
var METHOD_RE = /^[a-zA-Z_$][a-zA-Z0-9_$]*\s*\(/;
|
|
46
|
+
var VALID_FN_START_RE = /^(?:function\b|async\s+function\b|async\s*\(|\(|[a-zA-Z_$][a-zA-Z0-9_$]*\s*=>|async\s+[a-zA-Z_$])/;
|
|
47
|
+
function serializeFunction(fn) {
|
|
48
|
+
if (typeof fn !== "function") {
|
|
49
|
+
throw new TypeError("Expected a function");
|
|
50
|
+
}
|
|
51
|
+
const str = fn.toString();
|
|
52
|
+
if (typeof str !== "string" || str.length === 0) {
|
|
53
|
+
throw new TypeError(
|
|
54
|
+
"Function serialization returned an invalid result. This may indicate Function.prototype.toString has been tampered with."
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
if (NATIVE_CODE_RE.test(str)) {
|
|
58
|
+
throw new TypeError(
|
|
59
|
+
"Native functions cannot be serialized. Use an arrow function wrapper instead."
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
if (!VALID_FN_START_RE.test(str)) {
|
|
63
|
+
throw new TypeError(
|
|
64
|
+
"Function serialization produced unexpected output. Only arrow functions, function expressions, and async functions are supported."
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
if (METHOD_RE.test(str) && !str.startsWith("function") && !str.startsWith("async function") && !str.startsWith("async (") && !str.startsWith("async=") && !str.startsWith("(") && !str.includes("=>")) {
|
|
68
|
+
throw new TypeError(
|
|
69
|
+
"Class methods cannot be serialized. Use an arrow function wrapper instead."
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
return str;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// src/configure.ts
|
|
76
|
+
var import_node_os = require("os");
|
|
77
|
+
var DEFAULT_CONFIG = {
|
|
78
|
+
maxThreads: (0, import_node_os.availableParallelism)?.() ?? 4,
|
|
79
|
+
strategy: "fifo",
|
|
80
|
+
idleTimeout: 3e4,
|
|
81
|
+
adapter: "auto",
|
|
82
|
+
concurrency: 64
|
|
83
|
+
};
|
|
84
|
+
var currentConfig = { ...DEFAULT_CONFIG };
|
|
85
|
+
var configLocked = false;
|
|
86
|
+
function configure(opts) {
|
|
87
|
+
if (configLocked) {
|
|
88
|
+
throw new Error(
|
|
89
|
+
"configure() must be called before the first spawn(). The worker pool has already been initialized."
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
currentConfig = { ...currentConfig, ...opts };
|
|
93
|
+
}
|
|
94
|
+
function getConfig() {
|
|
95
|
+
configLocked = true;
|
|
96
|
+
return { ...currentConfig };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// src/runtime.ts
|
|
100
|
+
function detectRuntime() {
|
|
101
|
+
if (typeof globalThis.Bun !== "undefined") return "bun";
|
|
102
|
+
if (typeof globalThis.Deno !== "undefined") return "deno";
|
|
103
|
+
if (typeof globalThis.process !== "undefined" && globalThis.process.versions?.node)
|
|
104
|
+
return "node";
|
|
105
|
+
return "browser";
|
|
106
|
+
}
|
|
107
|
+
function detectCapability() {
|
|
108
|
+
const runtime = detectRuntime();
|
|
109
|
+
if (runtime === "node" || runtime === "bun") return "full-threads";
|
|
110
|
+
if (typeof globalThis.Worker !== "undefined") return "full-threads";
|
|
111
|
+
return "single-thread";
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// src/adapters/node.ts
|
|
115
|
+
var import_node_worker_threads = require("worker_threads");
|
|
116
|
+
|
|
117
|
+
// src/bootstrap.ts
|
|
118
|
+
var CHANNEL_PROXY_CODE = `
|
|
119
|
+
const __chCallbacks = new Map();
|
|
120
|
+
let __chRpcId = 0;
|
|
121
|
+
|
|
122
|
+
class __ChannelProxy {
|
|
123
|
+
constructor(id) {
|
|
124
|
+
this._id = id;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
_rpc(op, value) {
|
|
128
|
+
const correlationId = ++__chRpcId;
|
|
129
|
+
return new Promise((resolve, reject) => {
|
|
130
|
+
__chCallbacks.set(correlationId, { resolve, reject });
|
|
131
|
+
__postMsg({
|
|
132
|
+
type: 'channel-op',
|
|
133
|
+
channelId: this._id,
|
|
134
|
+
op,
|
|
135
|
+
correlationId,
|
|
136
|
+
value
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
send(value) {
|
|
142
|
+
return this._rpc('send', value);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
recv() {
|
|
146
|
+
return this._rpc('recv', undefined);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
close() {
|
|
150
|
+
__postMsg({
|
|
151
|
+
type: 'channel-op',
|
|
152
|
+
channelId: this._id,
|
|
153
|
+
op: 'close',
|
|
154
|
+
correlationId: ++__chRpcId
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
[Symbol.asyncIterator]() {
|
|
159
|
+
const proxy = this;
|
|
160
|
+
return {
|
|
161
|
+
async next() {
|
|
162
|
+
const value = await proxy.recv();
|
|
163
|
+
if (value === null) return { done: true, value: undefined };
|
|
164
|
+
return { done: false, value };
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function __handleChannelResult(msg) {
|
|
171
|
+
if (msg.type === 'channel-result') {
|
|
172
|
+
const cb = __chCallbacks.get(msg.correlationId);
|
|
173
|
+
if (cb) {
|
|
174
|
+
__chCallbacks.delete(msg.correlationId);
|
|
175
|
+
if (msg.error) {
|
|
176
|
+
cb.reject(new Error(msg.error));
|
|
177
|
+
} else {
|
|
178
|
+
cb.resolve(msg.value);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function __buildChannelProxies(channels) {
|
|
185
|
+
if (!channels) return undefined;
|
|
186
|
+
const proxies = {};
|
|
187
|
+
for (const name of Object.keys(channels)) {
|
|
188
|
+
proxies[name] = new __ChannelProxy(channels[name]);
|
|
189
|
+
}
|
|
190
|
+
return proxies;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function __execFn(fnStr, channels) {
|
|
194
|
+
if (channels) {
|
|
195
|
+
const __ch = __buildChannelProxies(channels);
|
|
196
|
+
const fn = new Function('__ch', 'return (' + fnStr + ')(__ch)');
|
|
197
|
+
return fn(__ch);
|
|
198
|
+
} else {
|
|
199
|
+
const fn = new Function('return (' + fnStr + ')()');
|
|
200
|
+
return fn();
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
`;
|
|
204
|
+
var NODE_BOOTSTRAP_CODE = `
|
|
205
|
+
'use strict';
|
|
206
|
+
const { parentPort } = require('worker_threads');
|
|
207
|
+
|
|
208
|
+
const __postMsg = (d) => parentPort.postMessage(d);
|
|
209
|
+
|
|
210
|
+
${CHANNEL_PROXY_CODE}
|
|
211
|
+
|
|
212
|
+
const cancelledTasks = new Set();
|
|
213
|
+
|
|
214
|
+
parentPort.on('message', (msg) => {
|
|
215
|
+
__handleChannelResult(msg);
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
parentPort.on('message', async (msg) => {
|
|
219
|
+
if (msg.type === 'execute') {
|
|
220
|
+
if (msg.concurrent) {
|
|
221
|
+
(async () => {
|
|
222
|
+
if (cancelledTasks.has(msg.taskId)) {
|
|
223
|
+
cancelledTasks.delete(msg.taskId);
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
try {
|
|
227
|
+
const result = await __execFn(msg.fnStr, msg.channels);
|
|
228
|
+
if (!cancelledTasks.has(msg.taskId)) {
|
|
229
|
+
parentPort.postMessage({ type: 'result', taskId: msg.taskId, value: result });
|
|
230
|
+
}
|
|
231
|
+
} catch (error) {
|
|
232
|
+
if (!cancelledTasks.has(msg.taskId)) {
|
|
233
|
+
parentPort.postMessage({
|
|
234
|
+
type: 'error',
|
|
235
|
+
taskId: msg.taskId,
|
|
236
|
+
message: error instanceof Error ? error.message : String(error),
|
|
237
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
} finally {
|
|
241
|
+
cancelledTasks.delete(msg.taskId);
|
|
242
|
+
}
|
|
243
|
+
})();
|
|
244
|
+
} else {
|
|
245
|
+
try {
|
|
246
|
+
const result = await __execFn(msg.fnStr, msg.channels);
|
|
247
|
+
parentPort.postMessage({ type: 'result', taskId: msg.taskId, value: result });
|
|
248
|
+
} catch (error) {
|
|
249
|
+
parentPort.postMessage({
|
|
250
|
+
type: 'error',
|
|
251
|
+
taskId: msg.taskId,
|
|
252
|
+
message: error instanceof Error ? error.message : String(error),
|
|
253
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
} else if (msg.type === 'cancel') {
|
|
258
|
+
cancelledTasks.add(msg.taskId);
|
|
259
|
+
} else if (msg.type === 'shutdown') {
|
|
260
|
+
process.exit(0);
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
parentPort.postMessage({ type: 'ready' });
|
|
265
|
+
`;
|
|
266
|
+
var WEB_BOOTSTRAP_CODE = `
|
|
267
|
+
const __postMsg = (d) => self.postMessage(d);
|
|
268
|
+
|
|
269
|
+
${CHANNEL_PROXY_CODE}
|
|
270
|
+
|
|
271
|
+
const cancelledTasks = new Set();
|
|
272
|
+
|
|
273
|
+
self.addEventListener('message', (event) => {
|
|
274
|
+
__handleChannelResult(event.data);
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
self.onmessage = async (event) => {
|
|
278
|
+
const msg = event.data;
|
|
279
|
+
if (msg.type === 'execute') {
|
|
280
|
+
if (msg.concurrent) {
|
|
281
|
+
(async () => {
|
|
282
|
+
if (cancelledTasks.has(msg.taskId)) {
|
|
283
|
+
cancelledTasks.delete(msg.taskId);
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
try {
|
|
287
|
+
const result = await __execFn(msg.fnStr, msg.channels);
|
|
288
|
+
if (!cancelledTasks.has(msg.taskId)) {
|
|
289
|
+
self.postMessage({ type: 'result', taskId: msg.taskId, value: result });
|
|
290
|
+
}
|
|
291
|
+
} catch (error) {
|
|
292
|
+
if (!cancelledTasks.has(msg.taskId)) {
|
|
293
|
+
self.postMessage({
|
|
294
|
+
type: 'error',
|
|
295
|
+
taskId: msg.taskId,
|
|
296
|
+
message: error instanceof Error ? error.message : String(error),
|
|
297
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
} finally {
|
|
301
|
+
cancelledTasks.delete(msg.taskId);
|
|
302
|
+
}
|
|
303
|
+
})();
|
|
304
|
+
} else {
|
|
305
|
+
try {
|
|
306
|
+
const result = await __execFn(msg.fnStr, msg.channels);
|
|
307
|
+
self.postMessage({ type: 'result', taskId: msg.taskId, value: result });
|
|
308
|
+
} catch (error) {
|
|
309
|
+
self.postMessage({
|
|
310
|
+
type: 'error',
|
|
311
|
+
taskId: msg.taskId,
|
|
312
|
+
message: error instanceof Error ? error.message : String(error),
|
|
313
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
} else if (msg.type === 'cancel') {
|
|
318
|
+
cancelledTasks.add(msg.taskId);
|
|
319
|
+
} else if (msg.type === 'shutdown') {
|
|
320
|
+
self.close();
|
|
321
|
+
}
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
self.postMessage({ type: 'ready' });
|
|
325
|
+
`;
|
|
326
|
+
|
|
327
|
+
// src/adapters/node.ts
|
|
328
|
+
var NodeManagedWorker = class {
|
|
329
|
+
worker;
|
|
330
|
+
constructor() {
|
|
331
|
+
this.worker = new import_node_worker_threads.Worker(NODE_BOOTSTRAP_CODE, { eval: true });
|
|
332
|
+
}
|
|
333
|
+
get id() {
|
|
334
|
+
return this.worker.threadId;
|
|
335
|
+
}
|
|
336
|
+
postMessage(data) {
|
|
337
|
+
this.worker.postMessage(data);
|
|
338
|
+
}
|
|
339
|
+
terminate() {
|
|
340
|
+
return this.worker.terminate();
|
|
341
|
+
}
|
|
342
|
+
on(event, handler) {
|
|
343
|
+
this.worker.on(event, handler);
|
|
344
|
+
}
|
|
345
|
+
unref() {
|
|
346
|
+
this.worker.unref();
|
|
347
|
+
}
|
|
348
|
+
ref() {
|
|
349
|
+
this.worker.ref();
|
|
350
|
+
}
|
|
351
|
+
};
|
|
352
|
+
var NodeWorkerAdapter = class {
|
|
353
|
+
createWorker() {
|
|
354
|
+
return new NodeManagedWorker();
|
|
355
|
+
}
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
// src/adapters/bun.ts
|
|
359
|
+
var import_node_fs = require("fs");
|
|
360
|
+
var import_node_path = require("path");
|
|
361
|
+
var import_node_os2 = require("os");
|
|
362
|
+
var workerIdCounter = 0;
|
|
363
|
+
var bootstrapFile = null;
|
|
364
|
+
function getBootstrapFile() {
|
|
365
|
+
if (!bootstrapFile) {
|
|
366
|
+
const dir = (0, import_node_fs.mkdtempSync)((0, import_node_path.join)((0, import_node_os2.tmpdir)(), "puru-"));
|
|
367
|
+
bootstrapFile = (0, import_node_path.join)(dir, "worker.js");
|
|
368
|
+
(0, import_node_fs.writeFileSync)(bootstrapFile, WEB_BOOTSTRAP_CODE);
|
|
369
|
+
}
|
|
370
|
+
return bootstrapFile;
|
|
371
|
+
}
|
|
372
|
+
var BunManagedWorker = class {
|
|
373
|
+
worker;
|
|
374
|
+
id;
|
|
375
|
+
constructor() {
|
|
376
|
+
this.id = ++workerIdCounter;
|
|
377
|
+
this.worker = new Worker(getBootstrapFile());
|
|
378
|
+
}
|
|
379
|
+
postMessage(data) {
|
|
380
|
+
this.worker.postMessage(data);
|
|
381
|
+
}
|
|
382
|
+
terminate() {
|
|
383
|
+
this.worker.terminate();
|
|
384
|
+
return Promise.resolve(0);
|
|
385
|
+
}
|
|
386
|
+
on(event, handler) {
|
|
387
|
+
if (event === "message") {
|
|
388
|
+
this.worker.addEventListener("message", (e) => {
|
|
389
|
+
handler(e.data);
|
|
390
|
+
});
|
|
391
|
+
} else if (event === "error") {
|
|
392
|
+
this.worker.addEventListener("error", (e) => {
|
|
393
|
+
handler(e.error ?? new Error(e.message));
|
|
394
|
+
});
|
|
395
|
+
} else if (event === "exit") {
|
|
396
|
+
this.worker.addEventListener("close", (e) => {
|
|
397
|
+
handler(e.code ?? 0);
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
unref() {
|
|
402
|
+
if ("unref" in this.worker && typeof this.worker.unref === "function") {
|
|
403
|
+
;
|
|
404
|
+
this.worker.unref();
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
ref() {
|
|
408
|
+
if ("ref" in this.worker && typeof this.worker.ref === "function") {
|
|
409
|
+
;
|
|
410
|
+
this.worker.ref();
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
};
|
|
414
|
+
var BunWorkerAdapter = class {
|
|
415
|
+
createWorker() {
|
|
416
|
+
return new BunManagedWorker();
|
|
417
|
+
}
|
|
418
|
+
};
|
|
419
|
+
|
|
420
|
+
// src/channel.ts
|
|
421
|
+
var channelIdCounter = 0;
|
|
422
|
+
var channelRegistry = /* @__PURE__ */ new Map();
|
|
423
|
+
var ChannelImpl = class {
|
|
424
|
+
/** @internal */
|
|
425
|
+
_id;
|
|
426
|
+
buffer = [];
|
|
427
|
+
capacity;
|
|
428
|
+
closed = false;
|
|
429
|
+
recvQueue = [];
|
|
430
|
+
sendQueue = [];
|
|
431
|
+
constructor(capacity) {
|
|
432
|
+
this._id = `__ch_${++channelIdCounter}`;
|
|
433
|
+
this.capacity = capacity;
|
|
434
|
+
channelRegistry.set(this._id, this);
|
|
435
|
+
}
|
|
436
|
+
send(value) {
|
|
437
|
+
if (this.closed) {
|
|
438
|
+
return Promise.reject(new Error("send on closed channel"));
|
|
439
|
+
}
|
|
440
|
+
const receiver = this.recvQueue.shift();
|
|
441
|
+
if (receiver) {
|
|
442
|
+
receiver.resolve(value);
|
|
443
|
+
return Promise.resolve();
|
|
444
|
+
}
|
|
445
|
+
if (this.buffer.length < this.capacity) {
|
|
446
|
+
this.buffer.push(value);
|
|
447
|
+
return Promise.resolve();
|
|
448
|
+
}
|
|
449
|
+
return new Promise((resolve, reject) => {
|
|
450
|
+
this.sendQueue.push({ value, resolve, reject });
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
recv() {
|
|
454
|
+
if (this.buffer.length > 0) {
|
|
455
|
+
const value = this.buffer.shift();
|
|
456
|
+
const sender2 = this.sendQueue.shift();
|
|
457
|
+
if (sender2) {
|
|
458
|
+
this.buffer.push(sender2.value);
|
|
459
|
+
sender2.resolve();
|
|
460
|
+
}
|
|
461
|
+
return Promise.resolve(value);
|
|
462
|
+
}
|
|
463
|
+
const sender = this.sendQueue.shift();
|
|
464
|
+
if (sender) {
|
|
465
|
+
sender.resolve();
|
|
466
|
+
return Promise.resolve(sender.value);
|
|
467
|
+
}
|
|
468
|
+
if (this.closed) {
|
|
469
|
+
return Promise.resolve(null);
|
|
470
|
+
}
|
|
471
|
+
return new Promise((resolve) => {
|
|
472
|
+
this.recvQueue.push({ resolve });
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
close() {
|
|
476
|
+
if (this.closed) return;
|
|
477
|
+
this.closed = true;
|
|
478
|
+
for (const receiver of this.recvQueue) {
|
|
479
|
+
receiver.resolve(null);
|
|
480
|
+
}
|
|
481
|
+
this.recvQueue = [];
|
|
482
|
+
for (const sender of this.sendQueue) {
|
|
483
|
+
sender.reject(new Error("send on closed channel"));
|
|
484
|
+
}
|
|
485
|
+
this.sendQueue = [];
|
|
486
|
+
}
|
|
487
|
+
async *[Symbol.asyncIterator]() {
|
|
488
|
+
while (true) {
|
|
489
|
+
const value = await this.recv();
|
|
490
|
+
if (value === null) return;
|
|
491
|
+
yield value;
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
};
|
|
495
|
+
function chan(capacity = 0) {
|
|
496
|
+
if (capacity < 0 || !Number.isInteger(capacity)) {
|
|
497
|
+
throw new RangeError("Channel capacity must be a non-negative integer");
|
|
498
|
+
}
|
|
499
|
+
return new ChannelImpl(capacity);
|
|
500
|
+
}
|
|
501
|
+
function getChannelById(id) {
|
|
502
|
+
return channelRegistry.get(id);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
// src/adapters/inline.ts
|
|
506
|
+
var inlineIdCounter = 0;
|
|
507
|
+
var InlineManagedWorker = class {
|
|
508
|
+
id;
|
|
509
|
+
messageHandlers = [];
|
|
510
|
+
errorHandlers = [];
|
|
511
|
+
exitHandlers = [];
|
|
512
|
+
terminated = false;
|
|
513
|
+
cancelledTasks = /* @__PURE__ */ new Set();
|
|
514
|
+
constructor() {
|
|
515
|
+
this.id = ++inlineIdCounter;
|
|
516
|
+
queueMicrotask(() => {
|
|
517
|
+
this.emit("message", { type: "ready" });
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
postMessage(data) {
|
|
521
|
+
if (this.terminated) return;
|
|
522
|
+
const msg = data;
|
|
523
|
+
if (msg.type === "execute") {
|
|
524
|
+
this.executeTask(msg.taskId, msg.fnStr, msg.concurrent ?? false, msg.channels);
|
|
525
|
+
} else if (msg.type === "cancel") {
|
|
526
|
+
this.cancelledTasks.add(msg.taskId);
|
|
527
|
+
} else if (msg.type === "channel-result") {
|
|
528
|
+
this.emit("message", msg);
|
|
529
|
+
} else if (msg.type === "shutdown") {
|
|
530
|
+
this.terminated = true;
|
|
531
|
+
this.emit("exit", 0);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
terminate() {
|
|
535
|
+
this.terminated = true;
|
|
536
|
+
this.emit("exit", 1);
|
|
537
|
+
return Promise.resolve(1);
|
|
538
|
+
}
|
|
539
|
+
on(event, handler) {
|
|
540
|
+
if (event === "message") this.messageHandlers.push(handler);
|
|
541
|
+
else if (event === "error") this.errorHandlers.push(handler);
|
|
542
|
+
else if (event === "exit") this.exitHandlers.push(handler);
|
|
543
|
+
}
|
|
544
|
+
unref() {
|
|
545
|
+
}
|
|
546
|
+
ref() {
|
|
547
|
+
}
|
|
548
|
+
emit(event, value) {
|
|
549
|
+
if (event === "message") {
|
|
550
|
+
for (const h of this.messageHandlers) h(value);
|
|
551
|
+
} else if (event === "error") {
|
|
552
|
+
for (const h of this.errorHandlers) h(value);
|
|
553
|
+
} else if (event === "exit") {
|
|
554
|
+
for (const h of this.exitHandlers) h(value);
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
buildChannelProxies(channels) {
|
|
558
|
+
const self = this;
|
|
559
|
+
const proxies = {};
|
|
560
|
+
for (const [name, channelId] of Object.entries(channels)) {
|
|
561
|
+
proxies[name] = {
|
|
562
|
+
_id: channelId,
|
|
563
|
+
async send(value) {
|
|
564
|
+
const ch = getChannelById(channelId);
|
|
565
|
+
if (!ch) throw new Error(`Channel ${channelId} not found`);
|
|
566
|
+
await ch.send(value);
|
|
567
|
+
},
|
|
568
|
+
async recv() {
|
|
569
|
+
const ch = getChannelById(channelId);
|
|
570
|
+
if (!ch) throw new Error(`Channel ${channelId} not found`);
|
|
571
|
+
return ch.recv();
|
|
572
|
+
},
|
|
573
|
+
close() {
|
|
574
|
+
const ch = getChannelById(channelId);
|
|
575
|
+
if (ch) ch.close();
|
|
576
|
+
},
|
|
577
|
+
[Symbol.asyncIterator]() {
|
|
578
|
+
const ch = getChannelById(channelId);
|
|
579
|
+
if (!ch) throw new Error(`Channel ${channelId} not found`);
|
|
580
|
+
return {
|
|
581
|
+
async next() {
|
|
582
|
+
const value = await ch.recv();
|
|
583
|
+
if (value === null) return { done: true, value: void 0 };
|
|
584
|
+
return { done: false, value };
|
|
585
|
+
}
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
return proxies;
|
|
591
|
+
}
|
|
592
|
+
executeTask(taskId, fnStr, concurrent, channels) {
|
|
593
|
+
queueMicrotask(async () => {
|
|
594
|
+
if (this.terminated) return;
|
|
595
|
+
if (concurrent && this.cancelledTasks.has(taskId)) {
|
|
596
|
+
this.cancelledTasks.delete(taskId);
|
|
597
|
+
return;
|
|
598
|
+
}
|
|
599
|
+
try {
|
|
600
|
+
let result;
|
|
601
|
+
if (channels) {
|
|
602
|
+
const proxies = this.buildChannelProxies(channels);
|
|
603
|
+
const fn = new Function("__ch", "return (" + fnStr + ")(__ch)");
|
|
604
|
+
result = await fn(proxies);
|
|
605
|
+
} else {
|
|
606
|
+
const fn = new Function("return (" + fnStr + ")()");
|
|
607
|
+
result = await fn();
|
|
608
|
+
}
|
|
609
|
+
if (concurrent && this.cancelledTasks.has(taskId)) {
|
|
610
|
+
this.cancelledTasks.delete(taskId);
|
|
611
|
+
return;
|
|
612
|
+
}
|
|
613
|
+
this.emit("message", { type: "result", taskId, value: result });
|
|
614
|
+
} catch (error) {
|
|
615
|
+
if (concurrent && this.cancelledTasks.has(taskId)) {
|
|
616
|
+
this.cancelledTasks.delete(taskId);
|
|
617
|
+
return;
|
|
618
|
+
}
|
|
619
|
+
this.emit("message", {
|
|
620
|
+
type: "error",
|
|
621
|
+
taskId,
|
|
622
|
+
message: error instanceof Error ? error.message : String(error),
|
|
623
|
+
stack: error instanceof Error ? error.stack : void 0
|
|
624
|
+
});
|
|
625
|
+
}
|
|
626
|
+
});
|
|
627
|
+
}
|
|
628
|
+
};
|
|
629
|
+
var InlineAdapter = class {
|
|
630
|
+
createWorker() {
|
|
631
|
+
return new InlineManagedWorker();
|
|
632
|
+
}
|
|
633
|
+
};
|
|
634
|
+
|
|
635
|
+
// src/pool.ts
|
|
636
|
+
var WorkerPool = class {
|
|
637
|
+
config;
|
|
638
|
+
adapter;
|
|
639
|
+
idleWorkers = [];
|
|
640
|
+
exclusiveWorkers = /* @__PURE__ */ new Map();
|
|
641
|
+
sharedWorkers = /* @__PURE__ */ new Map();
|
|
642
|
+
queues = {
|
|
643
|
+
high: [],
|
|
644
|
+
normal: [],
|
|
645
|
+
low: []
|
|
646
|
+
};
|
|
647
|
+
concurrentQueues = {
|
|
648
|
+
high: [],
|
|
649
|
+
normal: [],
|
|
650
|
+
low: []
|
|
651
|
+
};
|
|
652
|
+
allWorkers = /* @__PURE__ */ new Set();
|
|
653
|
+
idleTimers = /* @__PURE__ */ new Map();
|
|
654
|
+
pendingWorkerCount = 0;
|
|
655
|
+
pendingTasksForWorkers = [];
|
|
656
|
+
draining = false;
|
|
657
|
+
totalCompleted = 0;
|
|
658
|
+
totalFailed = 0;
|
|
659
|
+
taskMap = /* @__PURE__ */ new Map();
|
|
660
|
+
constructor(config, adapter) {
|
|
661
|
+
this.config = config;
|
|
662
|
+
this.adapter = adapter;
|
|
663
|
+
}
|
|
664
|
+
// --- Queue helpers ---
|
|
665
|
+
enqueue(task) {
|
|
666
|
+
this.queues[task.priority].push(task);
|
|
667
|
+
}
|
|
668
|
+
dequeue() {
|
|
669
|
+
return this.queues.high.shift() ?? this.queues.normal.shift() ?? this.queues.low.shift();
|
|
670
|
+
}
|
|
671
|
+
enqueueConcurrent(task) {
|
|
672
|
+
this.concurrentQueues[task.priority].push(task);
|
|
673
|
+
}
|
|
674
|
+
dequeueConcurrent() {
|
|
675
|
+
return this.concurrentQueues.high.shift() ?? this.concurrentQueues.normal.shift() ?? this.concurrentQueues.low.shift();
|
|
676
|
+
}
|
|
677
|
+
removeFromQueue(taskId) {
|
|
678
|
+
for (const priority of ["high", "normal", "low"]) {
|
|
679
|
+
const queue = this.queues[priority];
|
|
680
|
+
const idx = queue.findIndex((t) => t.id === taskId);
|
|
681
|
+
if (idx !== -1) {
|
|
682
|
+
return queue.splice(idx, 1)[0];
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
return void 0;
|
|
686
|
+
}
|
|
687
|
+
removeFromConcurrentQueue(taskId) {
|
|
688
|
+
for (const priority of ["high", "normal", "low"]) {
|
|
689
|
+
const queue = this.concurrentQueues[priority];
|
|
690
|
+
const idx = queue.findIndex((t) => t.id === taskId);
|
|
691
|
+
if (idx !== -1) {
|
|
692
|
+
return queue.splice(idx, 1)[0];
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
return void 0;
|
|
696
|
+
}
|
|
697
|
+
// --- Submit ---
|
|
698
|
+
submit(task) {
|
|
699
|
+
if (this.draining) {
|
|
700
|
+
task.reject(new Error("Pool is shutting down"));
|
|
701
|
+
return;
|
|
702
|
+
}
|
|
703
|
+
if (task.concurrent) {
|
|
704
|
+
this.submitConcurrent(task);
|
|
705
|
+
} else {
|
|
706
|
+
this.submitExclusive(task);
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
submitExclusive(task) {
|
|
710
|
+
const worker = this.idleWorkers.pop();
|
|
711
|
+
if (worker) {
|
|
712
|
+
this.dispatch(worker, task);
|
|
713
|
+
return;
|
|
714
|
+
}
|
|
715
|
+
const totalWorkers = this.allWorkers.size + this.pendingWorkerCount;
|
|
716
|
+
if (totalWorkers < this.config.maxThreads) {
|
|
717
|
+
this.pendingWorkerCount++;
|
|
718
|
+
this.pendingTasksForWorkers.push(task);
|
|
719
|
+
this.createAndReadyWorker();
|
|
720
|
+
return;
|
|
721
|
+
}
|
|
722
|
+
this.enqueue(task);
|
|
723
|
+
}
|
|
724
|
+
submitConcurrent(task) {
|
|
725
|
+
for (const [worker, tasks] of this.sharedWorkers) {
|
|
726
|
+
if (tasks.size < this.config.concurrency) {
|
|
727
|
+
this.dispatchConcurrent(worker, task);
|
|
728
|
+
return;
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
const idleWorker = this.idleWorkers.pop();
|
|
732
|
+
if (idleWorker) {
|
|
733
|
+
this.dispatchConcurrent(idleWorker, task);
|
|
734
|
+
return;
|
|
735
|
+
}
|
|
736
|
+
const totalWorkers = this.allWorkers.size + this.pendingWorkerCount;
|
|
737
|
+
if (totalWorkers < this.config.maxThreads) {
|
|
738
|
+
this.pendingWorkerCount++;
|
|
739
|
+
this.pendingTasksForWorkers.push(task);
|
|
740
|
+
this.createAndReadyWorker();
|
|
741
|
+
return;
|
|
742
|
+
}
|
|
743
|
+
this.enqueueConcurrent(task);
|
|
744
|
+
}
|
|
745
|
+
// --- Dispatch ---
|
|
746
|
+
dispatch(worker, task) {
|
|
747
|
+
const timer = this.idleTimers.get(worker);
|
|
748
|
+
if (timer) {
|
|
749
|
+
clearTimeout(timer);
|
|
750
|
+
this.idleTimers.delete(worker);
|
|
751
|
+
}
|
|
752
|
+
worker.ref();
|
|
753
|
+
this.exclusiveWorkers.set(task.id, worker);
|
|
754
|
+
this.taskMap.set(task.id, task);
|
|
755
|
+
const msg = {
|
|
756
|
+
type: "execute",
|
|
757
|
+
taskId: task.id,
|
|
758
|
+
fnStr: task.fnStr,
|
|
759
|
+
concurrent: false,
|
|
760
|
+
channels: task.channels
|
|
761
|
+
};
|
|
762
|
+
worker.postMessage(msg);
|
|
763
|
+
}
|
|
764
|
+
dispatchConcurrent(worker, task) {
|
|
765
|
+
const timer = this.idleTimers.get(worker);
|
|
766
|
+
if (timer) {
|
|
767
|
+
clearTimeout(timer);
|
|
768
|
+
this.idleTimers.delete(worker);
|
|
769
|
+
}
|
|
770
|
+
worker.ref();
|
|
771
|
+
if (!this.sharedWorkers.has(worker)) {
|
|
772
|
+
this.sharedWorkers.set(worker, /* @__PURE__ */ new Set());
|
|
773
|
+
}
|
|
774
|
+
this.sharedWorkers.get(worker).add(task.id);
|
|
775
|
+
this.taskMap.set(task.id, task);
|
|
776
|
+
const msg = {
|
|
777
|
+
type: "execute",
|
|
778
|
+
taskId: task.id,
|
|
779
|
+
fnStr: task.fnStr,
|
|
780
|
+
concurrent: true,
|
|
781
|
+
channels: task.channels
|
|
782
|
+
};
|
|
783
|
+
worker.postMessage(msg);
|
|
784
|
+
}
|
|
785
|
+
// --- Task completion ---
|
|
786
|
+
handleWorkerMessage(worker, response) {
|
|
787
|
+
if (response.type === "channel-op") {
|
|
788
|
+
this.handleChannelOp(worker, response);
|
|
789
|
+
return;
|
|
790
|
+
}
|
|
791
|
+
if (response.type === "result") {
|
|
792
|
+
const taskId = response.taskId;
|
|
793
|
+
this.resolveTask(taskId, response.value);
|
|
794
|
+
if (this.exclusiveWorkers.has(taskId)) {
|
|
795
|
+
this.exclusiveWorkers.delete(taskId);
|
|
796
|
+
this.assignNextOrIdle(worker);
|
|
797
|
+
} else {
|
|
798
|
+
const taskSet = this.sharedWorkers.get(worker);
|
|
799
|
+
if (taskSet) {
|
|
800
|
+
taskSet.delete(taskId);
|
|
801
|
+
this.assignNextConcurrentOrIdle(worker);
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
} else if (response.type === "error") {
|
|
805
|
+
const taskId = response.taskId;
|
|
806
|
+
const err = new Error(response.message);
|
|
807
|
+
if (response.stack) err.stack = response.stack;
|
|
808
|
+
this.rejectTask(taskId, err);
|
|
809
|
+
if (this.exclusiveWorkers.has(taskId)) {
|
|
810
|
+
this.exclusiveWorkers.delete(taskId);
|
|
811
|
+
this.assignNextOrIdle(worker);
|
|
812
|
+
} else {
|
|
813
|
+
const taskSet = this.sharedWorkers.get(worker);
|
|
814
|
+
if (taskSet) {
|
|
815
|
+
taskSet.delete(taskId);
|
|
816
|
+
this.assignNextConcurrentOrIdle(worker);
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
assignNextOrIdle(worker) {
|
|
822
|
+
if (!this.allWorkers.has(worker)) return;
|
|
823
|
+
const next = this.dequeue();
|
|
824
|
+
if (next) {
|
|
825
|
+
this.dispatch(worker, next);
|
|
826
|
+
return;
|
|
827
|
+
}
|
|
828
|
+
const concurrentNext = this.dequeueConcurrent();
|
|
829
|
+
if (concurrentNext) {
|
|
830
|
+
this.dispatchConcurrent(worker, concurrentNext);
|
|
831
|
+
return;
|
|
832
|
+
}
|
|
833
|
+
this.makeIdle(worker);
|
|
834
|
+
}
|
|
835
|
+
assignNextConcurrentOrIdle(worker) {
|
|
836
|
+
if (!this.allWorkers.has(worker)) return;
|
|
837
|
+
const taskSet = this.sharedWorkers.get(worker);
|
|
838
|
+
const currentCount = taskSet?.size ?? 0;
|
|
839
|
+
let filled = currentCount;
|
|
840
|
+
while (filled < this.config.concurrency) {
|
|
841
|
+
const next = this.dequeueConcurrent();
|
|
842
|
+
if (!next) break;
|
|
843
|
+
this.dispatchConcurrent(worker, next);
|
|
844
|
+
filled++;
|
|
845
|
+
}
|
|
846
|
+
const updatedSet = this.sharedWorkers.get(worker);
|
|
847
|
+
if (!updatedSet || updatedSet.size === 0) {
|
|
848
|
+
this.sharedWorkers.delete(worker);
|
|
849
|
+
const exclusiveTask = this.dequeue();
|
|
850
|
+
if (exclusiveTask) {
|
|
851
|
+
this.dispatch(worker, exclusiveTask);
|
|
852
|
+
} else {
|
|
853
|
+
this.makeIdle(worker);
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
makeIdle(worker) {
|
|
858
|
+
worker.unref();
|
|
859
|
+
this.idleWorkers.push(worker);
|
|
860
|
+
if (this.config.idleTimeout > 0) {
|
|
861
|
+
const timer = setTimeout(() => {
|
|
862
|
+
this.idleTimers.delete(worker);
|
|
863
|
+
const idx = this.idleWorkers.indexOf(worker);
|
|
864
|
+
if (idx !== -1) {
|
|
865
|
+
this.idleWorkers.splice(idx, 1);
|
|
866
|
+
}
|
|
867
|
+
this.allWorkers.delete(worker);
|
|
868
|
+
worker.terminate();
|
|
869
|
+
}, this.config.idleTimeout);
|
|
870
|
+
if (timer.unref) timer.unref();
|
|
871
|
+
this.idleTimers.set(worker, timer);
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
// --- Channel RPC ---
|
|
875
|
+
async handleChannelOp(worker, msg) {
|
|
876
|
+
const channel = getChannelById(msg.channelId);
|
|
877
|
+
if (!channel) {
|
|
878
|
+
worker.postMessage({
|
|
879
|
+
type: "channel-result",
|
|
880
|
+
correlationId: msg.correlationId,
|
|
881
|
+
error: `Channel ${msg.channelId} not found`
|
|
882
|
+
});
|
|
883
|
+
return;
|
|
884
|
+
}
|
|
885
|
+
try {
|
|
886
|
+
if (msg.op === "send") {
|
|
887
|
+
await channel.send(msg.value);
|
|
888
|
+
worker.postMessage({
|
|
889
|
+
type: "channel-result",
|
|
890
|
+
correlationId: msg.correlationId
|
|
891
|
+
});
|
|
892
|
+
} else if (msg.op === "recv") {
|
|
893
|
+
const value = await channel.recv();
|
|
894
|
+
worker.postMessage({
|
|
895
|
+
type: "channel-result",
|
|
896
|
+
correlationId: msg.correlationId,
|
|
897
|
+
value
|
|
898
|
+
});
|
|
899
|
+
} else if (msg.op === "close") {
|
|
900
|
+
channel.close();
|
|
901
|
+
worker.postMessage({
|
|
902
|
+
type: "channel-result",
|
|
903
|
+
correlationId: msg.correlationId
|
|
904
|
+
});
|
|
905
|
+
}
|
|
906
|
+
} catch (err) {
|
|
907
|
+
worker.postMessage({
|
|
908
|
+
type: "channel-result",
|
|
909
|
+
correlationId: msg.correlationId,
|
|
910
|
+
error: err instanceof Error ? err.message : String(err)
|
|
911
|
+
});
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
// --- Task resolution ---
|
|
915
|
+
resolveTask(taskId, value) {
|
|
916
|
+
const task = this.taskMap.get(taskId);
|
|
917
|
+
if (task) {
|
|
918
|
+
this.taskMap.delete(taskId);
|
|
919
|
+
this.totalCompleted++;
|
|
920
|
+
task.resolve(value);
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
rejectTask(taskId, reason) {
|
|
924
|
+
const task = this.taskMap.get(taskId);
|
|
925
|
+
if (task) {
|
|
926
|
+
this.taskMap.delete(taskId);
|
|
927
|
+
this.totalFailed++;
|
|
928
|
+
task.reject(reason);
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
// --- Cancellation ---
|
|
932
|
+
cancelTask(taskId) {
|
|
933
|
+
const removed = this.removeFromQueue(taskId);
|
|
934
|
+
if (removed) {
|
|
935
|
+
removed.reject(new DOMException("Task was cancelled", "AbortError"));
|
|
936
|
+
return;
|
|
937
|
+
}
|
|
938
|
+
const removedConcurrent = this.removeFromConcurrentQueue(taskId);
|
|
939
|
+
if (removedConcurrent) {
|
|
940
|
+
removedConcurrent.reject(new DOMException("Task was cancelled", "AbortError"));
|
|
941
|
+
return;
|
|
942
|
+
}
|
|
943
|
+
const exclusiveWorker = this.exclusiveWorkers.get(taskId);
|
|
944
|
+
if (exclusiveWorker) {
|
|
945
|
+
this.exclusiveWorkers.delete(taskId);
|
|
946
|
+
this.allWorkers.delete(exclusiveWorker);
|
|
947
|
+
this.taskMap.delete(taskId);
|
|
948
|
+
exclusiveWorker.terminate();
|
|
949
|
+
return;
|
|
950
|
+
}
|
|
951
|
+
for (const [worker, taskSet] of this.sharedWorkers) {
|
|
952
|
+
if (taskSet.has(taskId)) {
|
|
953
|
+
taskSet.delete(taskId);
|
|
954
|
+
this.taskMap.delete(taskId);
|
|
955
|
+
worker.postMessage({ type: "cancel", taskId });
|
|
956
|
+
if (taskSet.size === 0) {
|
|
957
|
+
this.sharedWorkers.delete(worker);
|
|
958
|
+
this.assignNextConcurrentOrIdle(worker);
|
|
959
|
+
}
|
|
960
|
+
return;
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
// --- Lifecycle ---
|
|
965
|
+
async drain() {
|
|
966
|
+
this.draining = true;
|
|
967
|
+
for (const priority of ["high", "normal", "low"]) {
|
|
968
|
+
for (const task of this.queues[priority]) {
|
|
969
|
+
task.reject(new Error("Pool is shutting down"));
|
|
970
|
+
}
|
|
971
|
+
this.queues[priority] = [];
|
|
972
|
+
}
|
|
973
|
+
for (const priority of ["high", "normal", "low"]) {
|
|
974
|
+
for (const task of this.concurrentQueues[priority]) {
|
|
975
|
+
task.reject(new Error("Pool is shutting down"));
|
|
976
|
+
}
|
|
977
|
+
this.concurrentQueues[priority] = [];
|
|
978
|
+
}
|
|
979
|
+
for (const [, taskSet] of this.sharedWorkers) {
|
|
980
|
+
for (const taskId of taskSet) {
|
|
981
|
+
this.taskMap.delete(taskId);
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
const terminatePromises = [];
|
|
985
|
+
for (const worker of this.allWorkers) {
|
|
986
|
+
const timer = this.idleTimers.get(worker);
|
|
987
|
+
if (timer) clearTimeout(timer);
|
|
988
|
+
terminatePromises.push(worker.terminate());
|
|
989
|
+
}
|
|
990
|
+
await Promise.all(terminatePromises);
|
|
991
|
+
this.idleWorkers = [];
|
|
992
|
+
this.exclusiveWorkers.clear();
|
|
993
|
+
this.sharedWorkers.clear();
|
|
994
|
+
this.allWorkers.clear();
|
|
995
|
+
this.idleTimers.clear();
|
|
996
|
+
}
|
|
997
|
+
resize(maxThreads) {
|
|
998
|
+
this.config = { ...this.config, maxThreads };
|
|
999
|
+
while (true) {
|
|
1000
|
+
const totalWorkers = this.allWorkers.size + this.pendingWorkerCount;
|
|
1001
|
+
if (totalWorkers >= maxThreads) break;
|
|
1002
|
+
const task = this.dequeue() ?? this.dequeueConcurrent();
|
|
1003
|
+
if (!task) break;
|
|
1004
|
+
this.pendingWorkerCount++;
|
|
1005
|
+
this.pendingTasksForWorkers.push(task);
|
|
1006
|
+
this.createAndReadyWorker();
|
|
1007
|
+
}
|
|
1008
|
+
while (this.allWorkers.size > maxThreads && this.idleWorkers.length > 0) {
|
|
1009
|
+
const worker = this.idleWorkers.pop();
|
|
1010
|
+
const timer = this.idleTimers.get(worker);
|
|
1011
|
+
if (timer) {
|
|
1012
|
+
clearTimeout(timer);
|
|
1013
|
+
this.idleTimers.delete(worker);
|
|
1014
|
+
}
|
|
1015
|
+
this.allWorkers.delete(worker);
|
|
1016
|
+
worker.terminate();
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
// --- Worker creation ---
|
|
1020
|
+
createAndReadyWorker() {
|
|
1021
|
+
const worker = this.adapter.createWorker();
|
|
1022
|
+
const onReady = () => {
|
|
1023
|
+
this.pendingWorkerCount--;
|
|
1024
|
+
this.allWorkers.add(worker);
|
|
1025
|
+
const task = this.pendingTasksForWorkers.shift();
|
|
1026
|
+
if (task) {
|
|
1027
|
+
if (task.concurrent) {
|
|
1028
|
+
this.dispatchConcurrent(worker, task);
|
|
1029
|
+
} else {
|
|
1030
|
+
this.dispatch(worker, task);
|
|
1031
|
+
}
|
|
1032
|
+
} else {
|
|
1033
|
+
this.makeIdle(worker);
|
|
1034
|
+
}
|
|
1035
|
+
};
|
|
1036
|
+
worker.on("message", (msg) => {
|
|
1037
|
+
const response = msg;
|
|
1038
|
+
if (response.type === "ready") {
|
|
1039
|
+
onReady();
|
|
1040
|
+
return;
|
|
1041
|
+
}
|
|
1042
|
+
this.handleWorkerMessage(worker, response);
|
|
1043
|
+
});
|
|
1044
|
+
worker.on("error", (err) => {
|
|
1045
|
+
for (const [taskId, w] of this.exclusiveWorkers) {
|
|
1046
|
+
if (w === worker) {
|
|
1047
|
+
this.exclusiveWorkers.delete(taskId);
|
|
1048
|
+
break;
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
const taskSet = this.sharedWorkers.get(worker);
|
|
1052
|
+
if (taskSet) {
|
|
1053
|
+
for (const taskId of taskSet) {
|
|
1054
|
+
this.rejectTask(taskId, err);
|
|
1055
|
+
}
|
|
1056
|
+
this.sharedWorkers.delete(worker);
|
|
1057
|
+
}
|
|
1058
|
+
});
|
|
1059
|
+
worker.on("exit", (_code) => {
|
|
1060
|
+
this.allWorkers.delete(worker);
|
|
1061
|
+
const timer = this.idleTimers.get(worker);
|
|
1062
|
+
if (timer) {
|
|
1063
|
+
clearTimeout(timer);
|
|
1064
|
+
this.idleTimers.delete(worker);
|
|
1065
|
+
}
|
|
1066
|
+
const idleIdx = this.idleWorkers.indexOf(worker);
|
|
1067
|
+
if (idleIdx !== -1) {
|
|
1068
|
+
this.idleWorkers.splice(idleIdx, 1);
|
|
1069
|
+
}
|
|
1070
|
+
for (const [taskId, w] of this.exclusiveWorkers) {
|
|
1071
|
+
if (w === worker) {
|
|
1072
|
+
this.exclusiveWorkers.delete(taskId);
|
|
1073
|
+
break;
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
const taskSet = this.sharedWorkers.get(worker);
|
|
1077
|
+
if (taskSet) {
|
|
1078
|
+
for (const taskId of taskSet) {
|
|
1079
|
+
this.rejectTask(taskId, new Error("Worker exited unexpectedly"));
|
|
1080
|
+
}
|
|
1081
|
+
this.sharedWorkers.delete(worker);
|
|
1082
|
+
}
|
|
1083
|
+
});
|
|
1084
|
+
}
|
|
1085
|
+
// --- Stats ---
|
|
1086
|
+
stats() {
|
|
1087
|
+
let concurrentTasks = 0;
|
|
1088
|
+
for (const taskSet of this.sharedWorkers.values()) {
|
|
1089
|
+
concurrentTasks += taskSet.size;
|
|
1090
|
+
}
|
|
1091
|
+
return {
|
|
1092
|
+
totalWorkers: this.allWorkers.size,
|
|
1093
|
+
idleWorkers: this.idleWorkers.length,
|
|
1094
|
+
busyWorkers: this.exclusiveWorkers.size,
|
|
1095
|
+
sharedWorkers: this.sharedWorkers.size,
|
|
1096
|
+
concurrentTasks,
|
|
1097
|
+
pendingWorkers: this.pendingWorkerCount,
|
|
1098
|
+
queuedTasks: {
|
|
1099
|
+
high: this.queues.high.length,
|
|
1100
|
+
normal: this.queues.normal.length,
|
|
1101
|
+
low: this.queues.low.length,
|
|
1102
|
+
total: this.queues.high.length + this.queues.normal.length + this.queues.low.length
|
|
1103
|
+
},
|
|
1104
|
+
queuedConcurrentTasks: {
|
|
1105
|
+
high: this.concurrentQueues.high.length,
|
|
1106
|
+
normal: this.concurrentQueues.normal.length,
|
|
1107
|
+
low: this.concurrentQueues.low.length,
|
|
1108
|
+
total: this.concurrentQueues.high.length + this.concurrentQueues.normal.length + this.concurrentQueues.low.length
|
|
1109
|
+
},
|
|
1110
|
+
totalCompleted: this.totalCompleted,
|
|
1111
|
+
totalFailed: this.totalFailed,
|
|
1112
|
+
maxThreads: this.config.maxThreads,
|
|
1113
|
+
concurrency: this.config.concurrency
|
|
1114
|
+
};
|
|
1115
|
+
}
|
|
1116
|
+
};
|
|
1117
|
+
var poolInstance = null;
|
|
1118
|
+
function createAdapter(adapterConfig) {
|
|
1119
|
+
if (adapterConfig === "inline") return new InlineAdapter();
|
|
1120
|
+
if (adapterConfig === "node") return new NodeWorkerAdapter();
|
|
1121
|
+
if (adapterConfig === "bun") return new BunWorkerAdapter();
|
|
1122
|
+
const capability = detectCapability();
|
|
1123
|
+
if (capability === "single-thread") {
|
|
1124
|
+
throw new Error(
|
|
1125
|
+
"puru requires a runtime with thread support (Node.js or Bun). Current runtime does not support worker threads."
|
|
1126
|
+
);
|
|
1127
|
+
}
|
|
1128
|
+
const runtime = detectRuntime();
|
|
1129
|
+
if (runtime === "bun") return new BunWorkerAdapter();
|
|
1130
|
+
return new NodeWorkerAdapter();
|
|
1131
|
+
}
|
|
1132
|
+
function getPool() {
|
|
1133
|
+
if (!poolInstance) {
|
|
1134
|
+
const config = getConfig();
|
|
1135
|
+
poolInstance = new WorkerPool(config, createAdapter(config.adapter));
|
|
1136
|
+
}
|
|
1137
|
+
return poolInstance;
|
|
1138
|
+
}
|
|
1139
|
+
function stats() {
|
|
1140
|
+
return getPool().stats();
|
|
1141
|
+
}
|
|
1142
|
+
function resize(maxThreads) {
|
|
1143
|
+
getPool().resize(maxThreads);
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
// src/spawn.ts
|
|
1147
|
+
var taskCounter = 0;
|
|
1148
|
+
function spawn(fn, opts) {
|
|
1149
|
+
const fnStr = serializeFunction(fn);
|
|
1150
|
+
const taskId = String(++taskCounter);
|
|
1151
|
+
const spawnStack = new Error().stack;
|
|
1152
|
+
let resolveFn;
|
|
1153
|
+
let rejectFn;
|
|
1154
|
+
let settled = false;
|
|
1155
|
+
const result = new Promise((resolve, reject) => {
|
|
1156
|
+
resolveFn = resolve;
|
|
1157
|
+
rejectFn = reject;
|
|
1158
|
+
});
|
|
1159
|
+
let channelMap;
|
|
1160
|
+
if (opts?.channels) {
|
|
1161
|
+
channelMap = {};
|
|
1162
|
+
for (const [name, ch] of Object.entries(opts.channels)) {
|
|
1163
|
+
const impl = ch;
|
|
1164
|
+
if (!impl._id) {
|
|
1165
|
+
throw new Error(`Channel "${name}" is not a valid puru channel`);
|
|
1166
|
+
}
|
|
1167
|
+
channelMap[name] = impl._id;
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
const task = {
|
|
1171
|
+
id: taskId,
|
|
1172
|
+
fnStr,
|
|
1173
|
+
priority: opts?.priority ?? "normal",
|
|
1174
|
+
concurrent: opts?.concurrent ?? false,
|
|
1175
|
+
channels: channelMap,
|
|
1176
|
+
resolve: (value) => {
|
|
1177
|
+
if (!settled) {
|
|
1178
|
+
settled = true;
|
|
1179
|
+
resolveFn(value);
|
|
1180
|
+
}
|
|
1181
|
+
},
|
|
1182
|
+
reject: (reason) => {
|
|
1183
|
+
if (!settled) {
|
|
1184
|
+
settled = true;
|
|
1185
|
+
if (reason instanceof Error && spawnStack) {
|
|
1186
|
+
const callerLine = spawnStack.split("\n").slice(2).join("\n");
|
|
1187
|
+
reason.stack = (reason.stack ?? reason.message) + "\n --- spawned at ---\n" + callerLine;
|
|
1188
|
+
}
|
|
1189
|
+
rejectFn(reason);
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
};
|
|
1193
|
+
getPool().submit(task);
|
|
1194
|
+
const cancel = () => {
|
|
1195
|
+
if (settled) return;
|
|
1196
|
+
settled = true;
|
|
1197
|
+
getPool().cancelTask(taskId);
|
|
1198
|
+
rejectFn(new DOMException("Task was cancelled", "AbortError"));
|
|
1199
|
+
};
|
|
1200
|
+
return { result, cancel };
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
// src/waitgroup.ts
|
|
1204
|
+
var WaitGroup = class {
|
|
1205
|
+
tasks = [];
|
|
1206
|
+
controller = new AbortController();
|
|
1207
|
+
get signal() {
|
|
1208
|
+
return this.controller.signal;
|
|
1209
|
+
}
|
|
1210
|
+
spawn(fn, opts) {
|
|
1211
|
+
if (this.controller.signal.aborted) {
|
|
1212
|
+
throw new Error("WaitGroup has been cancelled");
|
|
1213
|
+
}
|
|
1214
|
+
const handle = spawn(fn, opts);
|
|
1215
|
+
this.tasks.push(handle);
|
|
1216
|
+
}
|
|
1217
|
+
async wait() {
|
|
1218
|
+
return Promise.all(this.tasks.map((t) => t.result));
|
|
1219
|
+
}
|
|
1220
|
+
async waitSettled() {
|
|
1221
|
+
return Promise.allSettled(this.tasks.map((t) => t.result));
|
|
1222
|
+
}
|
|
1223
|
+
cancel() {
|
|
1224
|
+
this.controller.abort();
|
|
1225
|
+
for (const task of this.tasks) {
|
|
1226
|
+
task.cancel();
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
};
|
|
1230
|
+
|
|
1231
|
+
// src/errgroup.ts
|
|
1232
|
+
var ErrGroup = class {
|
|
1233
|
+
tasks = [];
|
|
1234
|
+
controller = new AbortController();
|
|
1235
|
+
firstError = void 0;
|
|
1236
|
+
hasError = false;
|
|
1237
|
+
get signal() {
|
|
1238
|
+
return this.controller.signal;
|
|
1239
|
+
}
|
|
1240
|
+
spawn(fn, opts) {
|
|
1241
|
+
if (this.controller.signal.aborted) {
|
|
1242
|
+
throw new Error("ErrGroup has been cancelled");
|
|
1243
|
+
}
|
|
1244
|
+
const handle = spawn(fn, opts);
|
|
1245
|
+
handle.result.catch((err) => {
|
|
1246
|
+
if (!this.hasError) {
|
|
1247
|
+
this.hasError = true;
|
|
1248
|
+
this.firstError = err;
|
|
1249
|
+
this.cancel();
|
|
1250
|
+
}
|
|
1251
|
+
});
|
|
1252
|
+
this.tasks.push(handle);
|
|
1253
|
+
}
|
|
1254
|
+
async wait() {
|
|
1255
|
+
const settled = await Promise.allSettled(this.tasks.map((t) => t.result));
|
|
1256
|
+
if (this.hasError) {
|
|
1257
|
+
throw this.firstError;
|
|
1258
|
+
}
|
|
1259
|
+
return settled.map((r) => {
|
|
1260
|
+
if (r.status === "fulfilled") return r.value;
|
|
1261
|
+
throw r.reason;
|
|
1262
|
+
});
|
|
1263
|
+
}
|
|
1264
|
+
cancel() {
|
|
1265
|
+
this.controller.abort();
|
|
1266
|
+
for (const task of this.tasks) {
|
|
1267
|
+
task.cancel();
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
};
|
|
1271
|
+
|
|
1272
|
+
// src/mutex.ts
|
|
1273
|
+
var Mutex = class {
|
|
1274
|
+
queue = [];
|
|
1275
|
+
locked = false;
|
|
1276
|
+
async lock() {
|
|
1277
|
+
if (!this.locked) {
|
|
1278
|
+
this.locked = true;
|
|
1279
|
+
return;
|
|
1280
|
+
}
|
|
1281
|
+
return new Promise((resolve) => {
|
|
1282
|
+
this.queue.push(resolve);
|
|
1283
|
+
});
|
|
1284
|
+
}
|
|
1285
|
+
unlock() {
|
|
1286
|
+
if (!this.locked) {
|
|
1287
|
+
throw new Error("Cannot unlock a mutex that is not locked");
|
|
1288
|
+
}
|
|
1289
|
+
const next = this.queue.shift();
|
|
1290
|
+
if (next) {
|
|
1291
|
+
next();
|
|
1292
|
+
} else {
|
|
1293
|
+
this.locked = false;
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
async withLock(fn) {
|
|
1297
|
+
await this.lock();
|
|
1298
|
+
try {
|
|
1299
|
+
return await fn();
|
|
1300
|
+
} finally {
|
|
1301
|
+
this.unlock();
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
get isLocked() {
|
|
1305
|
+
return this.locked;
|
|
1306
|
+
}
|
|
1307
|
+
};
|
|
1308
|
+
|
|
1309
|
+
// src/once.ts
|
|
1310
|
+
var Once = class {
|
|
1311
|
+
promise = null;
|
|
1312
|
+
called = false;
|
|
1313
|
+
async do(fn) {
|
|
1314
|
+
if (!this.called) {
|
|
1315
|
+
this.called = true;
|
|
1316
|
+
this.promise = Promise.resolve(fn());
|
|
1317
|
+
}
|
|
1318
|
+
return this.promise;
|
|
1319
|
+
}
|
|
1320
|
+
get done() {
|
|
1321
|
+
return this.called;
|
|
1322
|
+
}
|
|
1323
|
+
reset() {
|
|
1324
|
+
this.called = false;
|
|
1325
|
+
this.promise = null;
|
|
1326
|
+
}
|
|
1327
|
+
};
|
|
1328
|
+
|
|
1329
|
+
// src/select.ts
|
|
1330
|
+
function select(cases, opts) {
|
|
1331
|
+
if (cases.length === 0) {
|
|
1332
|
+
if (opts?.default) {
|
|
1333
|
+
opts.default();
|
|
1334
|
+
}
|
|
1335
|
+
return Promise.resolve();
|
|
1336
|
+
}
|
|
1337
|
+
if (opts?.default) {
|
|
1338
|
+
return new Promise((resolve, reject) => {
|
|
1339
|
+
let settled = false;
|
|
1340
|
+
for (const [promise, handler] of cases) {
|
|
1341
|
+
Promise.resolve(promise).then(
|
|
1342
|
+
(value) => {
|
|
1343
|
+
if (settled) return;
|
|
1344
|
+
settled = true;
|
|
1345
|
+
try {
|
|
1346
|
+
handler(value);
|
|
1347
|
+
resolve();
|
|
1348
|
+
} catch (err) {
|
|
1349
|
+
reject(err);
|
|
1350
|
+
}
|
|
1351
|
+
},
|
|
1352
|
+
(err) => {
|
|
1353
|
+
if (settled) return;
|
|
1354
|
+
settled = true;
|
|
1355
|
+
reject(err);
|
|
1356
|
+
}
|
|
1357
|
+
);
|
|
1358
|
+
}
|
|
1359
|
+
queueMicrotask(() => {
|
|
1360
|
+
if (settled) return;
|
|
1361
|
+
settled = true;
|
|
1362
|
+
try {
|
|
1363
|
+
opts.default();
|
|
1364
|
+
resolve();
|
|
1365
|
+
} catch (err) {
|
|
1366
|
+
reject(err);
|
|
1367
|
+
}
|
|
1368
|
+
});
|
|
1369
|
+
});
|
|
1370
|
+
}
|
|
1371
|
+
return new Promise((resolve, reject) => {
|
|
1372
|
+
let settled = false;
|
|
1373
|
+
cases.forEach(([promise, handler]) => {
|
|
1374
|
+
promise.then(
|
|
1375
|
+
(value) => {
|
|
1376
|
+
if (settled) return;
|
|
1377
|
+
settled = true;
|
|
1378
|
+
try {
|
|
1379
|
+
handler(value);
|
|
1380
|
+
resolve();
|
|
1381
|
+
} catch (err) {
|
|
1382
|
+
reject(err);
|
|
1383
|
+
}
|
|
1384
|
+
},
|
|
1385
|
+
(err) => {
|
|
1386
|
+
if (settled) return;
|
|
1387
|
+
settled = true;
|
|
1388
|
+
reject(err);
|
|
1389
|
+
}
|
|
1390
|
+
);
|
|
1391
|
+
});
|
|
1392
|
+
});
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1395
|
+
// src/after.ts
|
|
1396
|
+
function after(ms) {
|
|
1397
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
1398
|
+
}
|
|
1399
|
+
|
|
1400
|
+
// src/ticker.ts
|
|
1401
|
+
var Ticker = class {
|
|
1402
|
+
interval = null;
|
|
1403
|
+
resolve = null;
|
|
1404
|
+
stopped = false;
|
|
1405
|
+
ms;
|
|
1406
|
+
constructor(ms) {
|
|
1407
|
+
this.ms = ms;
|
|
1408
|
+
this.interval = setInterval(() => {
|
|
1409
|
+
if (this.resolve) {
|
|
1410
|
+
const r = this.resolve;
|
|
1411
|
+
this.resolve = null;
|
|
1412
|
+
r();
|
|
1413
|
+
}
|
|
1414
|
+
}, ms);
|
|
1415
|
+
if (this.interval.unref) this.interval.unref();
|
|
1416
|
+
}
|
|
1417
|
+
async tick() {
|
|
1418
|
+
if (this.stopped) return false;
|
|
1419
|
+
return new Promise((resolve) => {
|
|
1420
|
+
this.resolve = () => resolve(true);
|
|
1421
|
+
});
|
|
1422
|
+
}
|
|
1423
|
+
stop() {
|
|
1424
|
+
this.stopped = true;
|
|
1425
|
+
if (this.interval) {
|
|
1426
|
+
clearInterval(this.interval);
|
|
1427
|
+
this.interval = null;
|
|
1428
|
+
}
|
|
1429
|
+
if (this.resolve) {
|
|
1430
|
+
const r = this.resolve;
|
|
1431
|
+
this.resolve = null;
|
|
1432
|
+
r();
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
async *[Symbol.asyncIterator]() {
|
|
1436
|
+
while (await this.tick()) {
|
|
1437
|
+
yield;
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
};
|
|
1441
|
+
function ticker(ms) {
|
|
1442
|
+
return new Ticker(ms);
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1445
|
+
// src/registry.ts
|
|
1446
|
+
var registry = /* @__PURE__ */ new Map();
|
|
1447
|
+
var taskCounter2 = 0;
|
|
1448
|
+
function register(name, fn) {
|
|
1449
|
+
if (registry.has(name)) {
|
|
1450
|
+
throw new Error(`Task "${name}" is already registered`);
|
|
1451
|
+
}
|
|
1452
|
+
registry.set(name, fn);
|
|
1453
|
+
}
|
|
1454
|
+
function run(name, ...args) {
|
|
1455
|
+
const fn = registry.get(name);
|
|
1456
|
+
if (!fn) {
|
|
1457
|
+
throw new Error(`Task "${name}" is not registered. Call register() first.`);
|
|
1458
|
+
}
|
|
1459
|
+
const fnStr = serializeFunction(fn);
|
|
1460
|
+
const serializedArgs = args.map((a) => {
|
|
1461
|
+
const json = JSON.stringify(a);
|
|
1462
|
+
if (json === void 0) {
|
|
1463
|
+
throw new TypeError(
|
|
1464
|
+
`Argument of type ${typeof a} is not JSON-serializable. run() args must be JSON-serializable (no undefined, functions, symbols, or BigInt).`
|
|
1465
|
+
);
|
|
1466
|
+
}
|
|
1467
|
+
return json;
|
|
1468
|
+
});
|
|
1469
|
+
const wrapperStr = `() => (${fnStr})(${serializedArgs.join(", ")})`;
|
|
1470
|
+
const taskId = `reg_${++taskCounter2}`;
|
|
1471
|
+
const spawnStack = new Error().stack;
|
|
1472
|
+
let resolveFn;
|
|
1473
|
+
let rejectFn;
|
|
1474
|
+
const result = new Promise((resolve, reject) => {
|
|
1475
|
+
resolveFn = resolve;
|
|
1476
|
+
rejectFn = reject;
|
|
1477
|
+
});
|
|
1478
|
+
const task = {
|
|
1479
|
+
id: taskId,
|
|
1480
|
+
fnStr: wrapperStr,
|
|
1481
|
+
priority: "normal",
|
|
1482
|
+
concurrent: false,
|
|
1483
|
+
resolve: (value) => resolveFn(value),
|
|
1484
|
+
reject: (reason) => {
|
|
1485
|
+
if (reason instanceof Error && spawnStack) {
|
|
1486
|
+
const callerLine = spawnStack.split("\n").slice(2).join("\n");
|
|
1487
|
+
reason.stack = (reason.stack ?? reason.message) + "\n --- spawned at ---\n" + callerLine;
|
|
1488
|
+
}
|
|
1489
|
+
rejectFn(reason);
|
|
1490
|
+
}
|
|
1491
|
+
};
|
|
1492
|
+
getPool().submit(task);
|
|
1493
|
+
return result;
|
|
1494
|
+
}
|
|
1495
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1496
|
+
0 && (module.exports = {
|
|
1497
|
+
ErrGroup,
|
|
1498
|
+
Mutex,
|
|
1499
|
+
Once,
|
|
1500
|
+
Ticker,
|
|
1501
|
+
WaitGroup,
|
|
1502
|
+
after,
|
|
1503
|
+
chan,
|
|
1504
|
+
configure,
|
|
1505
|
+
detectCapability,
|
|
1506
|
+
detectRuntime,
|
|
1507
|
+
register,
|
|
1508
|
+
resize,
|
|
1509
|
+
run,
|
|
1510
|
+
select,
|
|
1511
|
+
spawn,
|
|
1512
|
+
stats,
|
|
1513
|
+
ticker
|
|
1514
|
+
});
|
|
1515
|
+
//# sourceMappingURL=index.cjs.map
|