@rspack/core 1.3.2 → 1.3.3

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.
@@ -0,0 +1,1080 @@
1
+ import {
2
+ isMovable,
3
+ isTaskQueue,
4
+ isTransferable,
5
+ kFieldCount,
6
+ kQueueOptions,
7
+ kRequestCountField,
8
+ kResponseCountField,
9
+ kTransferable,
10
+ kValue,
11
+ markMovable
12
+ } from "./chunk-UBWFVGJX.js";
13
+ import {
14
+ __privateAdd,
15
+ __privateGet,
16
+ __privateSet,
17
+ __publicField
18
+ } from "./chunk-6LX4VMOV.js";
19
+
20
+ // src/index.ts
21
+ import {
22
+ MessageChannel,
23
+ receiveMessageOnPort
24
+ } from "worker_threads";
25
+ import { once, EventEmitterAsyncResource } from "events";
26
+ import { AsyncResource } from "async_hooks";
27
+ import { fileURLToPath as fileURLToPath3, URL } from "url";
28
+ import { join } from "path";
29
+ import { inspect, types } from "util";
30
+ import assert from "assert";
31
+ import { performance } from "perf_hooks";
32
+ import { readFileSync } from "fs";
33
+
34
+ // src/physicalCpuCount.ts
35
+ import os from "os";
36
+ import childProcess from "child_process";
37
+ function exec(command) {
38
+ const output = childProcess.execSync(command, {
39
+ encoding: "utf8",
40
+ stdio: [null, null, null]
41
+ });
42
+ return output;
43
+ }
44
+ var amount;
45
+ try {
46
+ const platform = os.platform();
47
+ if (platform === "linux") {
48
+ const output1 = exec(
49
+ 'cat /proc/cpuinfo | grep "physical id" | sort |uniq | wc -l'
50
+ );
51
+ const output2 = exec(
52
+ 'cat /proc/cpuinfo | grep "core id" | sort | uniq | wc -l'
53
+ );
54
+ const physicalCpuAmount = parseInt(output1.trim(), 10);
55
+ const physicalCoreAmount = parseInt(output2.trim(), 10);
56
+ amount = physicalCpuAmount * physicalCoreAmount;
57
+ } else if (platform === "darwin") {
58
+ const output = exec("sysctl -n hw.physicalcpu_max");
59
+ amount = parseInt(output.trim(), 10);
60
+ } else if (platform === "win32") {
61
+ throw new Error();
62
+ } else {
63
+ const cores = os.cpus().filter(function(cpu, index) {
64
+ const hasHyperthreading = cpu.model.includes("Intel");
65
+ const isOdd = index % 2 === 1;
66
+ return !hasHyperthreading || isOdd;
67
+ });
68
+ amount = cores.length;
69
+ }
70
+ } catch {
71
+ amount = os.cpus().length;
72
+ }
73
+ if (amount === 0) {
74
+ amount = os.cpus().length;
75
+ }
76
+
77
+ // src/runtime/thread-worker.ts
78
+ import { fileURLToPath } from "url";
79
+ import { Worker } from "worker_threads";
80
+ var ThreadWorker = class {
81
+ constructor() {
82
+ __publicField(this, "name", "ThreadWorker");
83
+ __publicField(this, "runtime", "worker_threads");
84
+ __publicField(this, "thread");
85
+ __publicField(this, "threadId");
86
+ }
87
+ initialize(options) {
88
+ this.thread = new Worker(
89
+ fileURLToPath(import.meta.url + "/../entry/worker.js"),
90
+ options
91
+ );
92
+ this.threadId = this.thread.threadId;
93
+ }
94
+ async terminate() {
95
+ return this.thread.terminate();
96
+ }
97
+ postMessage(message, transferListItem) {
98
+ return this.thread.postMessage(message, transferListItem);
99
+ }
100
+ on(event, callback) {
101
+ return this.thread.on(event, callback);
102
+ }
103
+ once(event, callback) {
104
+ return this.thread.once(event, callback);
105
+ }
106
+ emit(event, ...data) {
107
+ return this.thread.emit(event, ...data);
108
+ }
109
+ ref() {
110
+ return this.thread.ref();
111
+ }
112
+ unref() {
113
+ return this.thread.unref();
114
+ }
115
+ setChannel() {
116
+ throw new Error(
117
+ "{ runtime: 'worker_threads' } doesn't support channel. Use transferListItem instead."
118
+ );
119
+ }
120
+ };
121
+
122
+ // src/runtime/process-worker.ts
123
+ import { fork } from "child_process";
124
+ import { MessagePort } from "worker_threads";
125
+ import { fileURLToPath as fileURLToPath2 } from "url";
126
+ var __tinypool_worker_message__ = true;
127
+ var SIGKILL_TIMEOUT = 1e3;
128
+ var ProcessWorker = class {
129
+ constructor() {
130
+ __publicField(this, "name", "ProcessWorker");
131
+ __publicField(this, "runtime", "child_process");
132
+ __publicField(this, "process");
133
+ __publicField(this, "threadId");
134
+ __publicField(this, "port");
135
+ __publicField(this, "channel");
136
+ __publicField(this, "waitForExit");
137
+ __publicField(this, "isTerminating", false);
138
+ __publicField(this, "onUnexpectedExit", () => {
139
+ this.process.emit("error", new Error("Worker exited unexpectedly"));
140
+ });
141
+ }
142
+ initialize(options) {
143
+ this.process = fork(
144
+ fileURLToPath2(import.meta.url + "/../entry/process.js"),
145
+ options.argv,
146
+ {
147
+ ...options,
148
+ stdio: "pipe",
149
+ env: {
150
+ ...options.env,
151
+ TINYPOOL_WORKER_ID: options.workerData[0].workerId.toString()
152
+ }
153
+ }
154
+ );
155
+ process.stdout.setMaxListeners(1 + process.stdout.getMaxListeners());
156
+ process.stderr.setMaxListeners(1 + process.stderr.getMaxListeners());
157
+ this.process.stdout?.pipe(process.stdout);
158
+ this.process.stderr?.pipe(process.stderr);
159
+ this.threadId = this.process.pid;
160
+ this.process.on("exit", this.onUnexpectedExit);
161
+ this.waitForExit = new Promise((r) => this.process.on("exit", r));
162
+ }
163
+ async terminate() {
164
+ this.isTerminating = true;
165
+ this.process.off("exit", this.onUnexpectedExit);
166
+ const sigkillTimeout = setTimeout(
167
+ () => this.process.kill("SIGKILL"),
168
+ SIGKILL_TIMEOUT
169
+ );
170
+ this.process.kill();
171
+ await this.waitForExit;
172
+ this.process.stdout?.unpipe(process.stdout);
173
+ this.process.stderr?.unpipe(process.stderr);
174
+ this.port?.close();
175
+ clearTimeout(sigkillTimeout);
176
+ }
177
+ setChannel(channel) {
178
+ this.channel = channel;
179
+ this.channel.onMessage((message) => {
180
+ this.send(message);
181
+ });
182
+ }
183
+ send(message) {
184
+ if (!this.isTerminating) {
185
+ this.process.send(message);
186
+ }
187
+ }
188
+ postMessage(message, transferListItem) {
189
+ transferListItem?.forEach((item) => {
190
+ if (item instanceof MessagePort) {
191
+ this.port = item;
192
+ }
193
+ });
194
+ if (this.port) {
195
+ this.port.on(
196
+ "message",
197
+ (message2) => this.send({
198
+ ...message2,
199
+ source: "port",
200
+ __tinypool_worker_message__
201
+ })
202
+ );
203
+ }
204
+ return this.send({
205
+ ...message,
206
+ source: "pool",
207
+ __tinypool_worker_message__
208
+ });
209
+ }
210
+ on(event, callback) {
211
+ return this.process.on(event, (data) => {
212
+ if (event === "error") {
213
+ return callback(data);
214
+ }
215
+ if (!data || !data.__tinypool_worker_message__) {
216
+ return this.channel?.postMessage(data);
217
+ }
218
+ if (data.source === "pool") {
219
+ callback(data);
220
+ } else if (data.source === "port") {
221
+ this.port.postMessage(data);
222
+ }
223
+ });
224
+ }
225
+ once(event, callback) {
226
+ return this.process.once(event, callback);
227
+ }
228
+ emit(event, ...data) {
229
+ return this.process.emit(event, ...data);
230
+ }
231
+ ref() {
232
+ return this.process.ref();
233
+ }
234
+ unref() {
235
+ this.port?.unref();
236
+ this.process.channel?.unref();
237
+ if (hasUnref(this.process.stdout)) {
238
+ this.process.stdout.unref();
239
+ }
240
+ if (hasUnref(this.process.stderr)) {
241
+ this.process.stderr.unref();
242
+ }
243
+ return this.process.unref();
244
+ }
245
+ };
246
+ function hasUnref(stream) {
247
+ return stream != null && "unref" in stream && typeof stream.unref === "function";
248
+ }
249
+
250
+ // src/index.ts
251
+ var cpuCount = amount;
252
+ function onabort(abortSignal, listener) {
253
+ if ("addEventListener" in abortSignal) {
254
+ abortSignal.addEventListener("abort", listener, { once: true });
255
+ } else {
256
+ abortSignal.once("abort", listener);
257
+ }
258
+ }
259
+ var AbortError = class extends Error {
260
+ constructor() {
261
+ super("The task has been aborted");
262
+ }
263
+ get name() {
264
+ return "AbortError";
265
+ }
266
+ };
267
+ var CancelError = class extends Error {
268
+ constructor() {
269
+ super("The task has been cancelled");
270
+ }
271
+ get name() {
272
+ return "CancelError";
273
+ }
274
+ };
275
+ var ArrayTaskQueue = class {
276
+ constructor() {
277
+ __publicField(this, "tasks", []);
278
+ }
279
+ get size() {
280
+ return this.tasks.length;
281
+ }
282
+ shift() {
283
+ return this.tasks.shift();
284
+ }
285
+ push(task) {
286
+ this.tasks.push(task);
287
+ }
288
+ remove(task) {
289
+ const index = this.tasks.indexOf(task);
290
+ assert.notStrictEqual(index, -1);
291
+ this.tasks.splice(index, 1);
292
+ }
293
+ cancel() {
294
+ while (this.tasks.length > 0) {
295
+ const task = this.tasks.pop();
296
+ task?.cancel();
297
+ }
298
+ }
299
+ };
300
+ var kDefaultOptions = {
301
+ filename: null,
302
+ name: "default",
303
+ runtime: "worker_threads",
304
+ minThreads: Math.max(cpuCount / 2, 1),
305
+ maxThreads: cpuCount,
306
+ idleTimeout: 0,
307
+ maxQueue: Infinity,
308
+ concurrentTasksPerWorker: 1,
309
+ useAtomics: true,
310
+ taskQueue: new ArrayTaskQueue(),
311
+ trackUnmanagedFds: true
312
+ };
313
+ var kDefaultRunOptions = {
314
+ transferList: void 0,
315
+ filename: null,
316
+ signal: null,
317
+ name: null
318
+ };
319
+ var _value;
320
+ var DirectlyTransferable = class {
321
+ constructor(value) {
322
+ __privateAdd(this, _value, void 0);
323
+ __privateSet(this, _value, value);
324
+ }
325
+ get [kTransferable]() {
326
+ return __privateGet(this, _value);
327
+ }
328
+ get [kValue]() {
329
+ return __privateGet(this, _value);
330
+ }
331
+ };
332
+ _value = new WeakMap();
333
+ var _view;
334
+ var ArrayBufferViewTransferable = class {
335
+ constructor(view) {
336
+ __privateAdd(this, _view, void 0);
337
+ __privateSet(this, _view, view);
338
+ }
339
+ get [kTransferable]() {
340
+ return __privateGet(this, _view).buffer;
341
+ }
342
+ get [kValue]() {
343
+ return __privateGet(this, _view);
344
+ }
345
+ };
346
+ _view = new WeakMap();
347
+ var taskIdCounter = 0;
348
+ function maybeFileURLToPath(filename) {
349
+ return filename.startsWith("file:") ? fileURLToPath3(new URL(filename)) : filename;
350
+ }
351
+ var TaskInfo = class extends AsyncResource {
352
+ constructor(task, transferList, filename, name, callback, abortSignal, triggerAsyncId, channel) {
353
+ super("Tinypool.Task", { requireManualDestroy: true, triggerAsyncId });
354
+ __publicField(this, "callback");
355
+ __publicField(this, "task");
356
+ __publicField(this, "transferList");
357
+ __publicField(this, "channel");
358
+ __publicField(this, "filename");
359
+ __publicField(this, "name");
360
+ __publicField(this, "taskId");
361
+ __publicField(this, "abortSignal");
362
+ __publicField(this, "abortListener", null);
363
+ __publicField(this, "workerInfo", null);
364
+ __publicField(this, "created");
365
+ __publicField(this, "started");
366
+ __publicField(this, "cancel");
367
+ this.callback = callback;
368
+ this.task = task;
369
+ this.transferList = transferList;
370
+ this.cancel = () => this.callback(new CancelError(), null);
371
+ this.channel = channel;
372
+ if (isMovable(task)) {
373
+ if (this.transferList == null) {
374
+ this.transferList = [];
375
+ }
376
+ this.transferList = this.transferList.concat(task[kTransferable]);
377
+ this.task = task[kValue];
378
+ }
379
+ this.filename = filename;
380
+ this.name = name;
381
+ this.taskId = taskIdCounter++;
382
+ this.abortSignal = abortSignal;
383
+ this.created = performance.now();
384
+ this.started = 0;
385
+ }
386
+ releaseTask() {
387
+ const ret = this.task;
388
+ this.task = null;
389
+ return ret;
390
+ }
391
+ done(err, result) {
392
+ this.emitDestroy();
393
+ this.runInAsyncScope(this.callback, null, err, result);
394
+ if (this.abortSignal && this.abortListener) {
395
+ if ("removeEventListener" in this.abortSignal && this.abortListener) {
396
+ this.abortSignal.removeEventListener("abort", this.abortListener);
397
+ } else {
398
+ ;
399
+ this.abortSignal.off(
400
+ "abort",
401
+ this.abortListener
402
+ );
403
+ }
404
+ }
405
+ }
406
+ get [kQueueOptions]() {
407
+ return kQueueOptions in this.task ? this.task[kQueueOptions] : null;
408
+ }
409
+ };
410
+ var AsynchronouslyCreatedResource = class {
411
+ constructor() {
412
+ __publicField(this, "onreadyListeners", []);
413
+ }
414
+ markAsReady() {
415
+ const listeners = this.onreadyListeners;
416
+ assert(listeners !== null);
417
+ this.onreadyListeners = null;
418
+ for (const listener of listeners) {
419
+ listener();
420
+ }
421
+ }
422
+ isReady() {
423
+ return this.onreadyListeners === null;
424
+ }
425
+ onReady(fn) {
426
+ if (this.onreadyListeners === null) {
427
+ fn();
428
+ return;
429
+ }
430
+ this.onreadyListeners.push(fn);
431
+ }
432
+ };
433
+ var AsynchronouslyCreatedResourcePool = class {
434
+ constructor(maximumUsage) {
435
+ __publicField(this, "pendingItems", /* @__PURE__ */ new Set());
436
+ __publicField(this, "readyItems", /* @__PURE__ */ new Set());
437
+ __publicField(this, "maximumUsage");
438
+ __publicField(this, "onAvailableListeners");
439
+ this.maximumUsage = maximumUsage;
440
+ this.onAvailableListeners = [];
441
+ }
442
+ add(item) {
443
+ this.pendingItems.add(item);
444
+ item.onReady(() => {
445
+ if (this.pendingItems.has(item)) {
446
+ this.pendingItems.delete(item);
447
+ this.readyItems.add(item);
448
+ this.maybeAvailable(item);
449
+ }
450
+ });
451
+ }
452
+ delete(item) {
453
+ this.pendingItems.delete(item);
454
+ this.readyItems.delete(item);
455
+ }
456
+ findAvailable() {
457
+ let minUsage = this.maximumUsage;
458
+ let candidate = null;
459
+ for (const item of this.readyItems) {
460
+ const usage = item.currentUsage();
461
+ if (usage === 0)
462
+ return item;
463
+ if (usage < minUsage) {
464
+ candidate = item;
465
+ minUsage = usage;
466
+ }
467
+ }
468
+ return candidate;
469
+ }
470
+ *[Symbol.iterator]() {
471
+ yield* this.pendingItems;
472
+ yield* this.readyItems;
473
+ }
474
+ get size() {
475
+ return this.pendingItems.size + this.readyItems.size;
476
+ }
477
+ maybeAvailable(item) {
478
+ if (item.currentUsage() < this.maximumUsage) {
479
+ for (const listener of this.onAvailableListeners) {
480
+ listener(item);
481
+ }
482
+ }
483
+ }
484
+ onAvailable(fn) {
485
+ this.onAvailableListeners.push(fn);
486
+ }
487
+ };
488
+ var Errors = {
489
+ ThreadTermination: () => new Error("Terminating worker thread"),
490
+ FilenameNotProvided: () => new Error("filename must be provided to run() or in options object"),
491
+ TaskQueueAtLimit: () => new Error("Task queue is at limit"),
492
+ NoTaskQueueAvailable: () => new Error("No task queue available and all Workers are busy")
493
+ };
494
+ var WorkerInfo = class extends AsynchronouslyCreatedResource {
495
+ constructor(worker, port, workerId, freeWorkerId, onMessage) {
496
+ super();
497
+ __publicField(this, "worker");
498
+ __publicField(this, "workerId");
499
+ __publicField(this, "freeWorkerId");
500
+ __publicField(this, "taskInfos");
501
+ __publicField(this, "idleTimeout", null);
502
+ __publicField(this, "port");
503
+ __publicField(this, "sharedBuffer");
504
+ __publicField(this, "lastSeenResponseCount", 0);
505
+ __publicField(this, "usedMemory");
506
+ __publicField(this, "onMessage");
507
+ __publicField(this, "shouldRecycle");
508
+ this.worker = worker;
509
+ this.workerId = workerId;
510
+ this.freeWorkerId = freeWorkerId;
511
+ this.port = port;
512
+ this.port.on(
513
+ "message",
514
+ (message) => this._handleResponse(message)
515
+ );
516
+ this.onMessage = onMessage;
517
+ this.taskInfos = /* @__PURE__ */ new Map();
518
+ this.sharedBuffer = new Int32Array(
519
+ new SharedArrayBuffer(kFieldCount * Int32Array.BYTES_PER_ELEMENT)
520
+ );
521
+ }
522
+ async destroy(timeout) {
523
+ let resolve;
524
+ let reject;
525
+ const ret = new Promise((res, rej) => {
526
+ resolve = res;
527
+ reject = rej;
528
+ });
529
+ const timer = timeout ? setTimeout(
530
+ () => reject(new Error("Failed to terminate worker")),
531
+ timeout
532
+ ) : null;
533
+ void this.worker.terminate().then(() => {
534
+ if (timer !== null) {
535
+ clearTimeout(timer);
536
+ }
537
+ this.port.close();
538
+ this.clearIdleTimeout();
539
+ for (const taskInfo of this.taskInfos.values()) {
540
+ taskInfo.done(Errors.ThreadTermination());
541
+ }
542
+ this.taskInfos.clear();
543
+ resolve();
544
+ });
545
+ return ret;
546
+ }
547
+ clearIdleTimeout() {
548
+ if (this.idleTimeout !== null) {
549
+ clearTimeout(this.idleTimeout);
550
+ this.idleTimeout = null;
551
+ }
552
+ }
553
+ ref() {
554
+ this.port.ref();
555
+ return this;
556
+ }
557
+ unref() {
558
+ this.port.unref();
559
+ return this;
560
+ }
561
+ _handleResponse(message) {
562
+ this.usedMemory = message.usedMemory;
563
+ this.onMessage(message);
564
+ if (this.taskInfos.size === 0) {
565
+ this.unref();
566
+ }
567
+ }
568
+ postTask(taskInfo) {
569
+ assert(!this.taskInfos.has(taskInfo.taskId));
570
+ const message = {
571
+ task: taskInfo.releaseTask(),
572
+ taskId: taskInfo.taskId,
573
+ filename: taskInfo.filename,
574
+ name: taskInfo.name
575
+ };
576
+ try {
577
+ if (taskInfo.channel) {
578
+ this.worker.setChannel?.(taskInfo.channel);
579
+ }
580
+ this.port.postMessage(message, taskInfo.transferList);
581
+ } catch (err) {
582
+ taskInfo.done(err);
583
+ return;
584
+ }
585
+ taskInfo.workerInfo = this;
586
+ this.taskInfos.set(taskInfo.taskId, taskInfo);
587
+ this.ref();
588
+ this.clearIdleTimeout();
589
+ Atomics.add(this.sharedBuffer, kRequestCountField, 1);
590
+ Atomics.notify(this.sharedBuffer, kRequestCountField, 1);
591
+ }
592
+ processPendingMessages() {
593
+ const actualResponseCount = Atomics.load(
594
+ this.sharedBuffer,
595
+ kResponseCountField
596
+ );
597
+ if (actualResponseCount !== this.lastSeenResponseCount) {
598
+ this.lastSeenResponseCount = actualResponseCount;
599
+ let entry;
600
+ while ((entry = receiveMessageOnPort(this.port)) !== void 0) {
601
+ this._handleResponse(entry.message);
602
+ }
603
+ }
604
+ }
605
+ isRunningAbortableTask() {
606
+ if (this.taskInfos.size !== 1)
607
+ return false;
608
+ const [first] = this.taskInfos;
609
+ const [, task] = first || [];
610
+ return task?.abortSignal !== null;
611
+ }
612
+ currentUsage() {
613
+ if (this.isRunningAbortableTask())
614
+ return Infinity;
615
+ return this.taskInfos.size;
616
+ }
617
+ };
618
+ var ThreadPool = class {
619
+ constructor(publicInterface, options) {
620
+ __publicField(this, "publicInterface");
621
+ __publicField(this, "workers");
622
+ __publicField(this, "workerIds");
623
+ // Map<workerId, isIdAvailable>
624
+ __publicField(this, "options");
625
+ __publicField(this, "taskQueue");
626
+ __publicField(this, "skipQueue", []);
627
+ __publicField(this, "completed", 0);
628
+ __publicField(this, "start", performance.now());
629
+ __publicField(this, "inProcessPendingMessages", false);
630
+ __publicField(this, "startingUp", false);
631
+ __publicField(this, "workerFailsDuringBootstrap", false);
632
+ this.publicInterface = publicInterface;
633
+ this.taskQueue = options.taskQueue || new ArrayTaskQueue();
634
+ const filename = options.filename ? maybeFileURLToPath(options.filename) : null;
635
+ this.options = { ...kDefaultOptions, ...options, filename, maxQueue: 0 };
636
+ if (options.maxThreads !== void 0 && this.options.minThreads >= options.maxThreads) {
637
+ this.options.minThreads = options.maxThreads;
638
+ }
639
+ if (options.minThreads !== void 0 && this.options.maxThreads <= options.minThreads) {
640
+ this.options.maxThreads = options.minThreads;
641
+ }
642
+ if (options.maxQueue === "auto") {
643
+ this.options.maxQueue = this.options.maxThreads ** 2;
644
+ } else {
645
+ this.options.maxQueue = options.maxQueue ?? kDefaultOptions.maxQueue;
646
+ }
647
+ this.workerIds = new Map(
648
+ new Array(this.options.maxThreads).fill(0).map((_, i) => [i + 1, true])
649
+ );
650
+ this.workers = new AsynchronouslyCreatedResourcePool(
651
+ this.options.concurrentTasksPerWorker
652
+ );
653
+ this.workers.onAvailable((w) => this._onWorkerAvailable(w));
654
+ this.startingUp = true;
655
+ this._ensureMinimumWorkers();
656
+ this.startingUp = false;
657
+ }
658
+ _ensureEnoughWorkersForTaskQueue() {
659
+ while (this.workers.size < this.taskQueue.size && this.workers.size < this.options.maxThreads) {
660
+ this._addNewWorker();
661
+ }
662
+ }
663
+ _ensureMaximumWorkers() {
664
+ while (this.workers.size < this.options.maxThreads) {
665
+ this._addNewWorker();
666
+ }
667
+ }
668
+ _ensureMinimumWorkers() {
669
+ while (this.workers.size < this.options.minThreads) {
670
+ this._addNewWorker();
671
+ }
672
+ }
673
+ _addNewWorker() {
674
+ const workerIds = this.workerIds;
675
+ let workerId;
676
+ workerIds.forEach((isIdAvailable, _workerId2) => {
677
+ if (isIdAvailable && !workerId) {
678
+ workerId = _workerId2;
679
+ workerIds.set(_workerId2, false);
680
+ }
681
+ });
682
+ const tinypoolPrivateData = { workerId };
683
+ const worker = this.options.runtime === "child_process" ? new ProcessWorker() : new ThreadWorker();
684
+ worker.initialize({
685
+ env: this.options.env,
686
+ argv: this.options.argv,
687
+ execArgv: this.options.execArgv,
688
+ resourceLimits: this.options.resourceLimits,
689
+ workerData: [
690
+ tinypoolPrivateData,
691
+ this.options.workerData
692
+ ],
693
+ trackUnmanagedFds: this.options.trackUnmanagedFds
694
+ });
695
+ const onMessage = (message2) => {
696
+ const { taskId, result } = message2;
697
+ const taskInfo = workerInfo.taskInfos.get(taskId);
698
+ workerInfo.taskInfos.delete(taskId);
699
+ if (!this.shouldRecycleWorker(taskInfo)) {
700
+ this.workers.maybeAvailable(workerInfo);
701
+ }
702
+ if (taskInfo === void 0) {
703
+ const err = new Error(
704
+ `Unexpected message from Worker: ${inspect(message2)}`
705
+ );
706
+ this.publicInterface.emit("error", err);
707
+ } else {
708
+ taskInfo.done(message2.error, result);
709
+ }
710
+ this._processPendingMessages();
711
+ };
712
+ const { port1, port2 } = new MessageChannel();
713
+ const workerInfo = new WorkerInfo(
714
+ worker,
715
+ port1,
716
+ workerId,
717
+ () => workerIds.set(workerId, true),
718
+ onMessage
719
+ );
720
+ if (this.startingUp) {
721
+ workerInfo.markAsReady();
722
+ }
723
+ const message = {
724
+ filename: this.options.filename,
725
+ name: this.options.name,
726
+ port: port2,
727
+ sharedBuffer: workerInfo.sharedBuffer,
728
+ useAtomics: this.options.useAtomics
729
+ };
730
+ worker.postMessage(message, [port2]);
731
+ worker.on("message", (message2) => {
732
+ if (message2.ready === true) {
733
+ if (workerInfo.currentUsage() === 0) {
734
+ workerInfo.unref();
735
+ }
736
+ if (!workerInfo.isReady()) {
737
+ workerInfo.markAsReady();
738
+ }
739
+ return;
740
+ }
741
+ worker.emit(
742
+ "error",
743
+ new Error(`Unexpected message on Worker: ${inspect(message2)}`)
744
+ );
745
+ });
746
+ worker.on("error", (err) => {
747
+ worker.ref = () => {
748
+ };
749
+ const taskInfos = [...workerInfo.taskInfos.values()];
750
+ workerInfo.taskInfos.clear();
751
+ void this._removeWorker(workerInfo);
752
+ if (workerInfo.isReady() && !this.workerFailsDuringBootstrap) {
753
+ this._ensureMinimumWorkers();
754
+ } else {
755
+ this.workerFailsDuringBootstrap = true;
756
+ }
757
+ if (taskInfos.length > 0) {
758
+ for (const taskInfo of taskInfos) {
759
+ taskInfo.done(err, null);
760
+ }
761
+ } else {
762
+ this.publicInterface.emit("error", err);
763
+ }
764
+ });
765
+ worker.unref();
766
+ port1.on("close", () => {
767
+ worker.ref();
768
+ });
769
+ this.workers.add(workerInfo);
770
+ }
771
+ _processPendingMessages() {
772
+ if (this.inProcessPendingMessages || !this.options.useAtomics) {
773
+ return;
774
+ }
775
+ this.inProcessPendingMessages = true;
776
+ try {
777
+ for (const workerInfo of this.workers) {
778
+ workerInfo.processPendingMessages();
779
+ }
780
+ } finally {
781
+ this.inProcessPendingMessages = false;
782
+ }
783
+ }
784
+ _removeWorker(workerInfo) {
785
+ workerInfo.freeWorkerId();
786
+ this.workers.delete(workerInfo);
787
+ return workerInfo.destroy(this.options.terminateTimeout);
788
+ }
789
+ _onWorkerAvailable(workerInfo) {
790
+ while ((this.taskQueue.size > 0 || this.skipQueue.length > 0) && workerInfo.currentUsage() < this.options.concurrentTasksPerWorker) {
791
+ const taskInfo = this.skipQueue.shift() || this.taskQueue.shift();
792
+ if (taskInfo.abortSignal && workerInfo.taskInfos.size > 0) {
793
+ this.skipQueue.push(taskInfo);
794
+ break;
795
+ }
796
+ const now = performance.now();
797
+ taskInfo.started = now;
798
+ workerInfo.postTask(taskInfo);
799
+ this._maybeDrain();
800
+ return;
801
+ }
802
+ if (workerInfo.taskInfos.size === 0 && this.workers.size > this.options.minThreads) {
803
+ workerInfo.idleTimeout = setTimeout(() => {
804
+ assert.strictEqual(workerInfo.taskInfos.size, 0);
805
+ if (this.workers.size > this.options.minThreads) {
806
+ void this._removeWorker(workerInfo);
807
+ }
808
+ }, this.options.idleTimeout).unref();
809
+ }
810
+ }
811
+ runTask(task, options) {
812
+ let { filename, name } = options;
813
+ const { transferList = [], signal = null, channel } = options;
814
+ if (filename == null) {
815
+ filename = this.options.filename;
816
+ }
817
+ if (name == null) {
818
+ name = this.options.name;
819
+ }
820
+ if (typeof filename !== "string") {
821
+ return Promise.reject(Errors.FilenameNotProvided());
822
+ }
823
+ filename = maybeFileURLToPath(filename);
824
+ let resolve;
825
+ let reject;
826
+ const ret = new Promise((res, rej) => {
827
+ resolve = res;
828
+ reject = rej;
829
+ });
830
+ const taskInfo = new TaskInfo(
831
+ task,
832
+ transferList,
833
+ filename,
834
+ name,
835
+ (err, result) => {
836
+ this.completed++;
837
+ if (err !== null) {
838
+ reject(err);
839
+ }
840
+ if (this.shouldRecycleWorker(taskInfo)) {
841
+ this._removeWorker(taskInfo.workerInfo).then(() => this._ensureMinimumWorkers()).then(() => this._ensureEnoughWorkersForTaskQueue()).then(() => resolve(result)).catch(reject);
842
+ } else {
843
+ resolve(result);
844
+ }
845
+ },
846
+ signal,
847
+ this.publicInterface.asyncResource.asyncId(),
848
+ channel
849
+ );
850
+ if (signal !== null) {
851
+ if (signal.aborted) {
852
+ return Promise.reject(new AbortError());
853
+ }
854
+ taskInfo.abortListener = () => {
855
+ reject(new AbortError());
856
+ if (taskInfo.workerInfo !== null) {
857
+ void this._removeWorker(taskInfo.workerInfo);
858
+ this._ensureMinimumWorkers();
859
+ } else {
860
+ this.taskQueue.remove(taskInfo);
861
+ }
862
+ };
863
+ onabort(signal, taskInfo.abortListener);
864
+ }
865
+ if (this.taskQueue.size > 0) {
866
+ const totalCapacity = this.options.maxQueue + this.pendingCapacity();
867
+ if (this.taskQueue.size >= totalCapacity) {
868
+ if (this.options.maxQueue === 0) {
869
+ return Promise.reject(Errors.NoTaskQueueAvailable());
870
+ } else {
871
+ return Promise.reject(Errors.TaskQueueAtLimit());
872
+ }
873
+ } else {
874
+ if (this.workers.size < this.options.maxThreads) {
875
+ this._addNewWorker();
876
+ }
877
+ this.taskQueue.push(taskInfo);
878
+ }
879
+ return ret;
880
+ }
881
+ let workerInfo = this.workers.findAvailable();
882
+ if (workerInfo !== null && workerInfo.currentUsage() > 0 && signal) {
883
+ workerInfo = null;
884
+ }
885
+ let waitingForNewWorker = false;
886
+ if ((workerInfo === null || workerInfo.currentUsage() > 0) && this.workers.size < this.options.maxThreads) {
887
+ this._addNewWorker();
888
+ waitingForNewWorker = true;
889
+ }
890
+ if (workerInfo === null) {
891
+ if (this.options.maxQueue <= 0 && !waitingForNewWorker) {
892
+ return Promise.reject(Errors.NoTaskQueueAvailable());
893
+ } else {
894
+ this.taskQueue.push(taskInfo);
895
+ }
896
+ return ret;
897
+ }
898
+ const now = performance.now();
899
+ taskInfo.started = now;
900
+ workerInfo.postTask(taskInfo);
901
+ this._maybeDrain();
902
+ return ret;
903
+ }
904
+ shouldRecycleWorker(taskInfo) {
905
+ if (taskInfo?.workerInfo?.shouldRecycle) {
906
+ return true;
907
+ }
908
+ if (this.options.isolateWorkers && taskInfo?.workerInfo) {
909
+ return true;
910
+ }
911
+ if (!this.options.isolateWorkers && this.options.maxMemoryLimitBeforeRecycle !== void 0 && (taskInfo?.workerInfo?.usedMemory || 0) > this.options.maxMemoryLimitBeforeRecycle) {
912
+ return true;
913
+ }
914
+ return false;
915
+ }
916
+ pendingCapacity() {
917
+ return this.workers.pendingItems.size * this.options.concurrentTasksPerWorker;
918
+ }
919
+ _maybeDrain() {
920
+ if (this.taskQueue.size === 0 && this.skipQueue.length === 0) {
921
+ this.publicInterface.emit("drain");
922
+ }
923
+ }
924
+ async destroy() {
925
+ while (this.skipQueue.length > 0) {
926
+ const taskInfo = this.skipQueue.shift();
927
+ taskInfo.done(new Error("Terminating worker thread"));
928
+ }
929
+ while (this.taskQueue.size > 0) {
930
+ const taskInfo = this.taskQueue.shift();
931
+ taskInfo.done(new Error("Terminating worker thread"));
932
+ }
933
+ const exitEvents = [];
934
+ while (this.workers.size > 0) {
935
+ const [workerInfo] = this.workers;
936
+ exitEvents.push(once(workerInfo.worker, "exit"));
937
+ void this._removeWorker(workerInfo);
938
+ }
939
+ await Promise.all(exitEvents);
940
+ }
941
+ async recycleWorkers(options = {}) {
942
+ const runtimeChanged = options?.runtime && options.runtime !== this.options.runtime;
943
+ if (options?.runtime) {
944
+ this.options.runtime = options.runtime;
945
+ }
946
+ if (this.options.isolateWorkers && !runtimeChanged) {
947
+ return;
948
+ }
949
+ const exitEvents = [];
950
+ Array.from(this.workers).filter((workerInfo) => {
951
+ if (workerInfo.currentUsage() === 0) {
952
+ exitEvents.push(once(workerInfo.worker, "exit"));
953
+ void this._removeWorker(workerInfo);
954
+ } else {
955
+ workerInfo.shouldRecycle = true;
956
+ }
957
+ });
958
+ await Promise.all(exitEvents);
959
+ this._ensureMinimumWorkers();
960
+ }
961
+ };
962
+ var _pool;
963
+ var Tinypool = class extends EventEmitterAsyncResource {
964
+ constructor(options = {}) {
965
+ if (options.minThreads !== void 0 && options.minThreads > 0 && options.minThreads < 1) {
966
+ options.minThreads = Math.max(
967
+ 1,
968
+ Math.floor(options.minThreads * cpuCount)
969
+ );
970
+ }
971
+ if (options.maxThreads !== void 0 && options.maxThreads > 0 && options.maxThreads < 1) {
972
+ options.maxThreads = Math.max(
973
+ 1,
974
+ Math.floor(options.maxThreads * cpuCount)
975
+ );
976
+ }
977
+ super({ ...options, name: "Tinypool" });
978
+ __privateAdd(this, _pool, void 0);
979
+ if (options.minThreads !== void 0 && options.maxThreads !== void 0 && options.minThreads > options.maxThreads) {
980
+ throw new RangeError(
981
+ "options.minThreads and options.maxThreads must not conflict"
982
+ );
983
+ }
984
+ __privateSet(this, _pool, new ThreadPool(this, options));
985
+ }
986
+ run(task, options = kDefaultRunOptions) {
987
+ const { transferList, filename, name, signal, runtime, channel } = options;
988
+ return __privateGet(this, _pool).runTask(task, {
989
+ transferList,
990
+ filename,
991
+ name,
992
+ signal,
993
+ runtime,
994
+ channel
995
+ });
996
+ }
997
+ async destroy() {
998
+ await __privateGet(this, _pool).destroy();
999
+ this.emitDestroy();
1000
+ }
1001
+ get options() {
1002
+ return __privateGet(this, _pool).options;
1003
+ }
1004
+ get threads() {
1005
+ const ret = [];
1006
+ for (const workerInfo of __privateGet(this, _pool).workers) {
1007
+ ret.push(workerInfo.worker);
1008
+ }
1009
+ return ret;
1010
+ }
1011
+ get queueSize() {
1012
+ const pool = __privateGet(this, _pool);
1013
+ return Math.max(pool.taskQueue.size - pool.pendingCapacity(), 0);
1014
+ }
1015
+ cancelPendingTasks() {
1016
+ const pool = __privateGet(this, _pool);
1017
+ pool.taskQueue.cancel();
1018
+ }
1019
+ async recycleWorkers(options = {}) {
1020
+ await __privateGet(this, _pool).recycleWorkers(options);
1021
+ }
1022
+ get completed() {
1023
+ return __privateGet(this, _pool).completed;
1024
+ }
1025
+ get duration() {
1026
+ return performance.now() - __privateGet(this, _pool).start;
1027
+ }
1028
+ static get isWorkerThread() {
1029
+ return process.__tinypool_state__?.isWorkerThread || false;
1030
+ }
1031
+ static get workerData() {
1032
+ return process.__tinypool_state__?.workerData || void 0;
1033
+ }
1034
+ static get version() {
1035
+ const { version } = JSON.parse(
1036
+ readFileSync(join(__dirname, "../package.json"), "utf-8")
1037
+ );
1038
+ return version;
1039
+ }
1040
+ static move(val) {
1041
+ if (val != null && typeof val === "object" && typeof val !== "function") {
1042
+ if (!isTransferable(val)) {
1043
+ if (types.isArrayBufferView(val)) {
1044
+ val = new ArrayBufferViewTransferable(val);
1045
+ } else {
1046
+ val = new DirectlyTransferable(val);
1047
+ }
1048
+ }
1049
+ markMovable(val);
1050
+ }
1051
+ return val;
1052
+ }
1053
+ static get transferableSymbol() {
1054
+ return kTransferable;
1055
+ }
1056
+ static get valueSymbol() {
1057
+ return kValue;
1058
+ }
1059
+ static get queueOptionsSymbol() {
1060
+ return kQueueOptions;
1061
+ }
1062
+ };
1063
+ _pool = new WeakMap();
1064
+ var _workerId = process.__tinypool_state__?.workerId;
1065
+ var src_default = Tinypool;
1066
+ export {
1067
+ Tinypool,
1068
+ src_default as default,
1069
+ isMovable,
1070
+ isTaskQueue,
1071
+ isTransferable,
1072
+ kFieldCount,
1073
+ kQueueOptions,
1074
+ kRequestCountField,
1075
+ kResponseCountField,
1076
+ kTransferable,
1077
+ kValue,
1078
+ markMovable,
1079
+ _workerId as workerId
1080
+ };