@rushstack/worker-pool 0.7.24 → 0.7.26
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/CHANGELOG.json +24 -0
- package/CHANGELOG.md +11 -1
- package/dist/tsdoc-metadata.json +1 -1
- package/dist/worker-pool.d.ts +1 -24
- package/lib-commonjs/WorkerPool.js +72 -72
- package/lib-commonjs/WorkerPool.js.map +1 -1
- package/lib-dts/WorkerPool.d.ts +1 -24
- package/lib-dts/WorkerPool.d.ts.map +1 -1
- package/lib-esm/WorkerPool.js +72 -72
- package/lib-esm/WorkerPool.js.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.json
CHANGED
|
@@ -1,6 +1,30 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rushstack/worker-pool",
|
|
3
3
|
"entries": [
|
|
4
|
+
{
|
|
5
|
+
"version": "0.7.26",
|
|
6
|
+
"tag": "@rushstack/worker-pool_v0.7.26",
|
|
7
|
+
"date": "Sat, 05 Sep 2026 00:15:08 GMT",
|
|
8
|
+
"comments": {
|
|
9
|
+
"dependency": [
|
|
10
|
+
{
|
|
11
|
+
"comment": "Updating dependency \"@rushstack/heft\" to `1.2.26`"
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"version": "0.7.25",
|
|
18
|
+
"tag": "@rushstack/worker-pool_v0.7.25",
|
|
19
|
+
"date": "Fri, 21 Aug 2026 15:16:35 GMT",
|
|
20
|
+
"comments": {
|
|
21
|
+
"dependency": [
|
|
22
|
+
{
|
|
23
|
+
"comment": "Updating dependency \"@rushstack/heft\" to `1.2.25`"
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
}
|
|
27
|
+
},
|
|
4
28
|
{
|
|
5
29
|
"version": "0.7.24",
|
|
6
30
|
"tag": "@rushstack/worker-pool_v0.7.24",
|
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
# Change Log - @rushstack/worker-pool
|
|
2
2
|
|
|
3
|
-
This log was last generated on
|
|
3
|
+
This log was last generated on Sat, 05 Sep 2026 00:15:08 GMT and should not be manually modified.
|
|
4
|
+
|
|
5
|
+
## 0.7.26
|
|
6
|
+
Sat, 05 Sep 2026 00:15:08 GMT
|
|
7
|
+
|
|
8
|
+
_Version update only_
|
|
9
|
+
|
|
10
|
+
## 0.7.25
|
|
11
|
+
Fri, 21 Aug 2026 15:16:35 GMT
|
|
12
|
+
|
|
13
|
+
_Version update only_
|
|
4
14
|
|
|
5
15
|
## 0.7.24
|
|
6
16
|
Thu, 20 Aug 2026 00:16:38 GMT
|
package/dist/tsdoc-metadata.json
CHANGED
package/dist/worker-pool.d.ts
CHANGED
|
@@ -56,20 +56,9 @@ export declare const WORKER_ID_SYMBOL: unique symbol;
|
|
|
56
56
|
* @internal
|
|
57
57
|
*/
|
|
58
58
|
export declare class WorkerPool {
|
|
59
|
+
#private;
|
|
59
60
|
id: string;
|
|
60
61
|
maxWorkers: number;
|
|
61
|
-
private readonly _alive;
|
|
62
|
-
private _error;
|
|
63
|
-
private _finishing;
|
|
64
|
-
private readonly _idle;
|
|
65
|
-
private _nextId;
|
|
66
|
-
private readonly _onComplete;
|
|
67
|
-
private readonly _onWorkerDestroyed;
|
|
68
|
-
private readonly _pending;
|
|
69
|
-
private readonly _prepare;
|
|
70
|
-
private readonly _workerData;
|
|
71
|
-
private readonly _workerScript;
|
|
72
|
-
private readonly _workerResourceLimits;
|
|
73
62
|
constructor(options: IWorkerPoolOptions);
|
|
74
63
|
/**
|
|
75
64
|
* Gets the count of active workers.
|
|
@@ -102,18 +91,6 @@ export declare class WorkerPool {
|
|
|
102
91
|
* @param allowCreate - If creating new workers is allowed (subject to maxSize)
|
|
103
92
|
*/
|
|
104
93
|
checkoutWorkerAsync(allowCreate: boolean): Promise<Worker>;
|
|
105
|
-
/**
|
|
106
|
-
* Creates a new worker if allowed by maxSize.
|
|
107
|
-
*/
|
|
108
|
-
private _createWorker;
|
|
109
|
-
/**
|
|
110
|
-
* Cleans up a worker
|
|
111
|
-
*/
|
|
112
|
-
private _destroyWorker;
|
|
113
|
-
/**
|
|
114
|
-
* Notifies all pending callbacks that an error has occurred and switches this pool into error state.
|
|
115
|
-
*/
|
|
116
|
-
private _onError;
|
|
117
94
|
}
|
|
118
95
|
|
|
119
96
|
export { }
|
|
@@ -17,102 +17,102 @@ exports.WORKER_ID_SYMBOL = Symbol('workerId');
|
|
|
17
17
|
class WorkerPool {
|
|
18
18
|
id;
|
|
19
19
|
maxWorkers;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
20
|
+
#alive;
|
|
21
|
+
#error;
|
|
22
|
+
#finishing;
|
|
23
|
+
#idle;
|
|
24
|
+
#nextId;
|
|
25
|
+
#onComplete;
|
|
26
|
+
#onWorkerDestroyed;
|
|
27
|
+
#pending;
|
|
28
|
+
#prepare;
|
|
29
|
+
#workerData;
|
|
30
|
+
#workerScript;
|
|
31
|
+
#workerResourceLimits;
|
|
32
32
|
constructor(options) {
|
|
33
33
|
const { id, maxWorkers, onWorkerDestroyed, prepareWorker, workerData, workerScriptPath, workerResourceLimits } = options;
|
|
34
34
|
this.id = id;
|
|
35
35
|
this.maxWorkers = maxWorkers;
|
|
36
|
-
this
|
|
37
|
-
this
|
|
38
|
-
this
|
|
39
|
-
this
|
|
40
|
-
this
|
|
41
|
-
this
|
|
42
|
-
this
|
|
43
|
-
this
|
|
44
|
-
this
|
|
45
|
-
this
|
|
46
|
-
this
|
|
47
|
-
this
|
|
36
|
+
this.#alive = [];
|
|
37
|
+
this.#error = undefined;
|
|
38
|
+
this.#finishing = false;
|
|
39
|
+
this.#idle = [];
|
|
40
|
+
this.#nextId = 0;
|
|
41
|
+
this.#onComplete = [];
|
|
42
|
+
this.#onWorkerDestroyed = onWorkerDestroyed;
|
|
43
|
+
this.#pending = [];
|
|
44
|
+
this.#prepare = prepareWorker;
|
|
45
|
+
this.#workerData = workerData;
|
|
46
|
+
this.#workerScript = workerScriptPath;
|
|
47
|
+
this.#workerResourceLimits = workerResourceLimits;
|
|
48
48
|
}
|
|
49
49
|
/**
|
|
50
50
|
* Gets the count of active workers.
|
|
51
51
|
*/
|
|
52
52
|
getActiveCount() {
|
|
53
|
-
return this.
|
|
53
|
+
return this.#alive.length - this.#idle.length;
|
|
54
54
|
}
|
|
55
55
|
/**
|
|
56
56
|
* Gets the count of idle workers.
|
|
57
57
|
*/
|
|
58
58
|
getIdleCount() {
|
|
59
|
-
return this.
|
|
59
|
+
return this.#idle.length;
|
|
60
60
|
}
|
|
61
61
|
/**
|
|
62
62
|
* Gets the count of live workers.
|
|
63
63
|
*/
|
|
64
64
|
getLiveCount() {
|
|
65
|
-
return this.
|
|
65
|
+
return this.#alive.length;
|
|
66
66
|
}
|
|
67
67
|
/**
|
|
68
68
|
* Tells the pool to shut down when all workers are done.
|
|
69
69
|
* Returns a promise that will be fulfilled if all workers finish successfully, or reject with the first error.
|
|
70
70
|
*/
|
|
71
71
|
async finishAsync() {
|
|
72
|
-
this
|
|
73
|
-
if (this
|
|
74
|
-
throw this
|
|
72
|
+
this.#finishing = true;
|
|
73
|
+
if (this.#error) {
|
|
74
|
+
throw this.#error;
|
|
75
75
|
}
|
|
76
|
-
if (!this.
|
|
76
|
+
if (!this.#alive.length) {
|
|
77
77
|
// The pool has no live workers, this is a no-op
|
|
78
78
|
return;
|
|
79
79
|
}
|
|
80
80
|
// Clean up all idle workers
|
|
81
|
-
for (const worker of this.
|
|
81
|
+
for (const worker of this.#idle.splice(0)) {
|
|
82
82
|
worker.postMessage(false);
|
|
83
83
|
}
|
|
84
84
|
// There are still active workers, wait for them to clean up.
|
|
85
|
-
await new Promise((resolve, reject) => this.
|
|
85
|
+
await new Promise((resolve, reject) => this.#onComplete.push([resolve, reject]));
|
|
86
86
|
}
|
|
87
87
|
/**
|
|
88
88
|
* Resets the pool and allows more work
|
|
89
89
|
*/
|
|
90
90
|
reset() {
|
|
91
|
-
this
|
|
92
|
-
this
|
|
91
|
+
this.#finishing = false;
|
|
92
|
+
this.#error = undefined;
|
|
93
93
|
}
|
|
94
94
|
/**
|
|
95
95
|
* Returns a worker to the pool. If the pool is finishing, deallocates the worker.
|
|
96
96
|
* @param worker - The worker to free
|
|
97
97
|
*/
|
|
98
98
|
checkinWorker(worker) {
|
|
99
|
-
if (this
|
|
99
|
+
if (this.#error) {
|
|
100
100
|
// Shut down the worker (failure)
|
|
101
101
|
worker.postMessage(false);
|
|
102
102
|
return;
|
|
103
103
|
}
|
|
104
|
-
const next = this.
|
|
104
|
+
const next = this.#pending.shift();
|
|
105
105
|
if (next) {
|
|
106
106
|
// Perform the next unit of work;
|
|
107
107
|
next[0](worker);
|
|
108
108
|
}
|
|
109
|
-
else if (this
|
|
109
|
+
else if (this.#finishing) {
|
|
110
110
|
// Shut down the worker (success)
|
|
111
111
|
worker.postMessage(false);
|
|
112
112
|
}
|
|
113
113
|
else {
|
|
114
114
|
// No pending work, idle the workers
|
|
115
|
-
this.
|
|
115
|
+
this.#idle.push(worker);
|
|
116
116
|
}
|
|
117
117
|
}
|
|
118
118
|
/**
|
|
@@ -120,68 +120,68 @@ class WorkerPool {
|
|
|
120
120
|
* @param allowCreate - If creating new workers is allowed (subject to maxSize)
|
|
121
121
|
*/
|
|
122
122
|
async checkoutWorkerAsync(allowCreate) {
|
|
123
|
-
if (this
|
|
124
|
-
throw this
|
|
123
|
+
if (this.#error) {
|
|
124
|
+
throw this.#error;
|
|
125
125
|
}
|
|
126
|
-
let worker = this.
|
|
126
|
+
let worker = this.#idle.shift();
|
|
127
127
|
if (!worker && allowCreate) {
|
|
128
|
-
worker = this
|
|
128
|
+
worker = this.#createWorker();
|
|
129
129
|
}
|
|
130
130
|
if (worker) {
|
|
131
131
|
return worker;
|
|
132
132
|
}
|
|
133
133
|
return await new Promise((resolve, reject) => {
|
|
134
|
-
this.
|
|
134
|
+
this.#pending.push([resolve, reject]);
|
|
135
135
|
});
|
|
136
136
|
}
|
|
137
137
|
/**
|
|
138
138
|
* Creates a new worker if allowed by maxSize.
|
|
139
139
|
*/
|
|
140
|
-
|
|
141
|
-
if (this.
|
|
140
|
+
#createWorker() {
|
|
141
|
+
if (this.#alive.length >= this.maxWorkers) {
|
|
142
142
|
return;
|
|
143
143
|
}
|
|
144
|
-
const worker = new node_worker_threads_1.Worker(this
|
|
144
|
+
const worker = new node_worker_threads_1.Worker(this.#workerScript, {
|
|
145
145
|
eval: false,
|
|
146
|
-
workerData: this
|
|
147
|
-
resourceLimits: this
|
|
146
|
+
workerData: this.#workerData,
|
|
147
|
+
resourceLimits: this.#workerResourceLimits
|
|
148
148
|
});
|
|
149
|
-
const id = `${this.id}#${++this
|
|
149
|
+
const id = `${this.id}#${++this.#nextId}`;
|
|
150
150
|
worker[exports.WORKER_ID_SYMBOL] = id;
|
|
151
|
-
this.
|
|
151
|
+
this.#alive.push(worker);
|
|
152
152
|
worker.on('error', (err) => {
|
|
153
|
-
this
|
|
154
|
-
this
|
|
153
|
+
this.#onError(err);
|
|
154
|
+
this.#destroyWorker(worker);
|
|
155
155
|
});
|
|
156
156
|
worker.once('exit', (exitCode) => {
|
|
157
157
|
if (exitCode !== 0) {
|
|
158
|
-
this
|
|
158
|
+
this.#onError(new Error(`Worker ${id} exited with code ${exitCode}`));
|
|
159
159
|
}
|
|
160
|
-
this
|
|
160
|
+
this.#destroyWorker(worker);
|
|
161
161
|
});
|
|
162
|
-
if (this
|
|
163
|
-
this
|
|
162
|
+
if (this.#prepare) {
|
|
163
|
+
this.#prepare(worker);
|
|
164
164
|
}
|
|
165
165
|
return worker;
|
|
166
166
|
}
|
|
167
167
|
/**
|
|
168
168
|
* Cleans up a worker
|
|
169
169
|
*/
|
|
170
|
-
|
|
171
|
-
const aliveIndex = this.
|
|
170
|
+
#destroyWorker(worker) {
|
|
171
|
+
const aliveIndex = this.#alive.indexOf(worker);
|
|
172
172
|
if (aliveIndex >= 0) {
|
|
173
|
-
this.
|
|
173
|
+
this.#alive.splice(aliveIndex, 1);
|
|
174
174
|
}
|
|
175
|
-
const freeIndex = this.
|
|
175
|
+
const freeIndex = this.#idle.indexOf(worker);
|
|
176
176
|
if (freeIndex >= 0) {
|
|
177
|
-
this.
|
|
177
|
+
this.#idle.splice(freeIndex, 1);
|
|
178
178
|
}
|
|
179
179
|
worker.unref();
|
|
180
|
-
if (this
|
|
181
|
-
this
|
|
180
|
+
if (this.#onWorkerDestroyed) {
|
|
181
|
+
this.#onWorkerDestroyed();
|
|
182
182
|
}
|
|
183
|
-
if (!this.
|
|
184
|
-
for (const [resolve] of this.
|
|
183
|
+
if (!this.#alive.length && !this.#error) {
|
|
184
|
+
for (const [resolve] of this.#onComplete.splice(0)) {
|
|
185
185
|
resolve();
|
|
186
186
|
}
|
|
187
187
|
}
|
|
@@ -189,13 +189,13 @@ class WorkerPool {
|
|
|
189
189
|
/**
|
|
190
190
|
* Notifies all pending callbacks that an error has occurred and switches this pool into error state.
|
|
191
191
|
*/
|
|
192
|
-
|
|
193
|
-
this
|
|
194
|
-
for (const [, reject] of this.
|
|
195
|
-
reject(this
|
|
192
|
+
#onError(error) {
|
|
193
|
+
this.#error = error;
|
|
194
|
+
for (const [, reject] of this.#pending.splice(0)) {
|
|
195
|
+
reject(this.#error);
|
|
196
196
|
}
|
|
197
|
-
for (const [, reject] of this.
|
|
198
|
-
reject(this
|
|
197
|
+
for (const [, reject] of this.#onComplete.splice(0)) {
|
|
198
|
+
reject(this.#error);
|
|
199
199
|
}
|
|
200
200
|
}
|
|
201
201
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WorkerPool.js","sourceRoot":"","sources":["../src/WorkerPool.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { type ResourceLimits, Worker } from 'node:worker_threads';\n\n/**\n * Symbol to read the ID off of a worker\n * @internal\n */\nexport const WORKER_ID_SYMBOL: unique symbol = Symbol('workerId');\n\n/**\n * @internal\n */\nexport interface IWorkerPoolOptions {\n /**\n * Identifier for this pool, to assign to its workers for tracking\n */\n id: string;\n /**\n * Maximum number of concurrent workers this WorkerPool may spawn.\n */\n maxWorkers: number;\n /**\n * Optional callback invoked when a worker is destroyed.\n */\n onWorkerDestroyed?: () => void;\n /**\n * Optional callback invoked on a newly created worker.\n */\n prepareWorker?: (worker: Worker) => void;\n /**\n * Optional data to pass to workers when they are initialized.\n * Will be subjected to the Structured Clone algorithm.\n */\n workerData?: unknown;\n /**\n * Absolute path to the worker script.\n */\n workerScriptPath: string;\n\n /**\n * Optional resource limits for the workers.\n */\n workerResourceLimits?: ResourceLimits;\n}\n\n/**\n * Manages a pool of workers.\n * Workers will be shutdown by sending them the boolean value `false` in a postMessage.\n * @internal\n */\nexport class WorkerPool {\n public id: string;\n public maxWorkers: number;\n\n private readonly _alive: Worker[];\n private _error: Error | undefined;\n private _finishing: boolean;\n private readonly _idle: Worker[];\n private _nextId: number;\n private readonly _onComplete: [() => void, (error: Error) => void][];\n private readonly _onWorkerDestroyed: (() => void) | undefined;\n private readonly _pending: [(worker: Worker) => void, (error: Error) => void][];\n private readonly _prepare: ((worker: Worker) => void) | undefined;\n private readonly _workerData: unknown;\n private readonly _workerScript: string;\n private readonly _workerResourceLimits: ResourceLimits | undefined;\n\n public constructor(options: IWorkerPoolOptions) {\n const {\n id,\n maxWorkers,\n onWorkerDestroyed,\n prepareWorker,\n workerData,\n workerScriptPath,\n workerResourceLimits\n } = options;\n\n this.id = id;\n this.maxWorkers = maxWorkers;\n this._alive = [];\n this._error = undefined;\n this._finishing = false;\n this._idle = [];\n this._nextId = 0;\n this._onComplete = [];\n this._onWorkerDestroyed = onWorkerDestroyed;\n this._pending = [];\n this._prepare = prepareWorker;\n this._workerData = workerData;\n this._workerScript = workerScriptPath;\n this._workerResourceLimits = workerResourceLimits;\n }\n\n /**\n * Gets the count of active workers.\n */\n public getActiveCount(): number {\n return this._alive.length - this._idle.length;\n }\n\n /**\n * Gets the count of idle workers.\n */\n public getIdleCount(): number {\n return this._idle.length;\n }\n\n /**\n * Gets the count of live workers.\n */\n public getLiveCount(): number {\n return this._alive.length;\n }\n\n /**\n * Tells the pool to shut down when all workers are done.\n * Returns a promise that will be fulfilled if all workers finish successfully, or reject with the first error.\n */\n public async finishAsync(): Promise<void> {\n this._finishing = true;\n\n if (this._error) {\n throw this._error;\n }\n\n if (!this._alive.length) {\n // The pool has no live workers, this is a no-op\n return;\n }\n\n // Clean up all idle workers\n for (const worker of this._idle.splice(0)) {\n worker.postMessage(false);\n }\n\n // There are still active workers, wait for them to clean up.\n await new Promise<void>((resolve, reject) => this._onComplete.push([resolve, reject]));\n }\n\n /**\n * Resets the pool and allows more work\n */\n public reset(): void {\n this._finishing = false;\n this._error = undefined;\n }\n\n /**\n * Returns a worker to the pool. If the pool is finishing, deallocates the worker.\n * @param worker - The worker to free\n */\n public checkinWorker(worker: Worker): void {\n if (this._error) {\n // Shut down the worker (failure)\n worker.postMessage(false);\n return;\n }\n\n const next: [(worker: Worker) => void, unknown] | undefined = this._pending.shift();\n\n if (next) {\n // Perform the next unit of work;\n next[0](worker);\n } else if (this._finishing) {\n // Shut down the worker (success)\n worker.postMessage(false);\n } else {\n // No pending work, idle the workers\n this._idle.push(worker);\n }\n }\n\n /**\n * Checks out a currently available worker or waits for the next free worker.\n * @param allowCreate - If creating new workers is allowed (subject to maxSize)\n */\n public async checkoutWorkerAsync(allowCreate: boolean): Promise<Worker> {\n if (this._error) {\n throw this._error;\n }\n\n let worker: Worker | undefined = this._idle.shift();\n if (!worker && allowCreate) {\n worker = this._createWorker();\n }\n\n if (worker) {\n return worker;\n }\n\n return await new Promise((resolve: (worker: Worker) => void, reject: (error: Error) => void) => {\n this._pending.push([resolve, reject]);\n });\n }\n\n /**\n * Creates a new worker if allowed by maxSize.\n */\n private _createWorker(): Worker | undefined {\n if (this._alive.length >= this.maxWorkers) {\n return;\n }\n\n const worker: Worker & {\n [WORKER_ID_SYMBOL]?: string;\n } = new Worker(this._workerScript, {\n eval: false,\n workerData: this._workerData,\n resourceLimits: this._workerResourceLimits\n });\n\n const id: string = `${this.id}#${++this._nextId}`;\n worker[WORKER_ID_SYMBOL] = id;\n\n this._alive.push(worker);\n\n worker.on('error', (err) => {\n this._onError(err);\n this._destroyWorker(worker);\n });\n\n worker.once('exit', (exitCode) => {\n if (exitCode !== 0) {\n this._onError(new Error(`Worker ${id} exited with code ${exitCode}`));\n }\n this._destroyWorker(worker);\n });\n\n if (this._prepare) {\n this._prepare(worker);\n }\n\n return worker;\n }\n\n /**\n * Cleans up a worker\n */\n private _destroyWorker(worker: Worker): void {\n const aliveIndex: number = this._alive.indexOf(worker);\n if (aliveIndex >= 0) {\n this._alive.splice(aliveIndex, 1);\n }\n\n const freeIndex: number = this._idle.indexOf(worker);\n if (freeIndex >= 0) {\n this._idle.splice(freeIndex, 1);\n }\n\n worker.unref();\n\n if (this._onWorkerDestroyed) {\n this._onWorkerDestroyed();\n }\n\n if (!this._alive.length && !this._error) {\n for (const [resolve] of this._onComplete.splice(0)) {\n resolve();\n }\n }\n }\n\n /**\n * Notifies all pending callbacks that an error has occurred and switches this pool into error state.\n */\n private _onError(error: Error): void {\n this._error = error;\n\n for (const [, reject] of this._pending.splice(0)) {\n reject(this._error);\n }\n\n for (const [, reject] of this._onComplete.splice(0)) {\n reject(this._error);\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"WorkerPool.js","sourceRoot":"","sources":["../src/WorkerPool.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { type ResourceLimits, Worker } from 'node:worker_threads';\n\n/**\n * Symbol to read the ID off of a worker\n * @internal\n */\nexport const WORKER_ID_SYMBOL: unique symbol = Symbol('workerId');\n\n/**\n * @internal\n */\nexport interface IWorkerPoolOptions {\n /**\n * Identifier for this pool, to assign to its workers for tracking\n */\n id: string;\n /**\n * Maximum number of concurrent workers this WorkerPool may spawn.\n */\n maxWorkers: number;\n /**\n * Optional callback invoked when a worker is destroyed.\n */\n onWorkerDestroyed?: () => void;\n /**\n * Optional callback invoked on a newly created worker.\n */\n prepareWorker?: (worker: Worker) => void;\n /**\n * Optional data to pass to workers when they are initialized.\n * Will be subjected to the Structured Clone algorithm.\n */\n workerData?: unknown;\n /**\n * Absolute path to the worker script.\n */\n workerScriptPath: string;\n\n /**\n * Optional resource limits for the workers.\n */\n workerResourceLimits?: ResourceLimits;\n}\n\n/**\n * Manages a pool of workers.\n * Workers will be shutdown by sending them the boolean value `false` in a postMessage.\n * @internal\n */\nexport class WorkerPool {\n public id: string;\n public maxWorkers: number;\n\n readonly #alive: Worker[];\n #error: Error | undefined;\n #finishing: boolean;\n readonly #idle: Worker[];\n #nextId: number;\n readonly #onComplete: [() => void, (error: Error) => void][];\n readonly #onWorkerDestroyed: (() => void) | undefined;\n readonly #pending: [(worker: Worker) => void, (error: Error) => void][];\n readonly #prepare: ((worker: Worker) => void) | undefined;\n readonly #workerData: unknown;\n readonly #workerScript: string;\n readonly #workerResourceLimits: ResourceLimits | undefined;\n\n public constructor(options: IWorkerPoolOptions) {\n const {\n id,\n maxWorkers,\n onWorkerDestroyed,\n prepareWorker,\n workerData,\n workerScriptPath,\n workerResourceLimits\n } = options;\n\n this.id = id;\n this.maxWorkers = maxWorkers;\n this.#alive = [];\n this.#error = undefined;\n this.#finishing = false;\n this.#idle = [];\n this.#nextId = 0;\n this.#onComplete = [];\n this.#onWorkerDestroyed = onWorkerDestroyed;\n this.#pending = [];\n this.#prepare = prepareWorker;\n this.#workerData = workerData;\n this.#workerScript = workerScriptPath;\n this.#workerResourceLimits = workerResourceLimits;\n }\n\n /**\n * Gets the count of active workers.\n */\n public getActiveCount(): number {\n return this.#alive.length - this.#idle.length;\n }\n\n /**\n * Gets the count of idle workers.\n */\n public getIdleCount(): number {\n return this.#idle.length;\n }\n\n /**\n * Gets the count of live workers.\n */\n public getLiveCount(): number {\n return this.#alive.length;\n }\n\n /**\n * Tells the pool to shut down when all workers are done.\n * Returns a promise that will be fulfilled if all workers finish successfully, or reject with the first error.\n */\n public async finishAsync(): Promise<void> {\n this.#finishing = true;\n\n if (this.#error) {\n throw this.#error;\n }\n\n if (!this.#alive.length) {\n // The pool has no live workers, this is a no-op\n return;\n }\n\n // Clean up all idle workers\n for (const worker of this.#idle.splice(0)) {\n worker.postMessage(false);\n }\n\n // There are still active workers, wait for them to clean up.\n await new Promise<void>((resolve, reject) => this.#onComplete.push([resolve, reject]));\n }\n\n /**\n * Resets the pool and allows more work\n */\n public reset(): void {\n this.#finishing = false;\n this.#error = undefined;\n }\n\n /**\n * Returns a worker to the pool. If the pool is finishing, deallocates the worker.\n * @param worker - The worker to free\n */\n public checkinWorker(worker: Worker): void {\n if (this.#error) {\n // Shut down the worker (failure)\n worker.postMessage(false);\n return;\n }\n\n const next: [(worker: Worker) => void, unknown] | undefined = this.#pending.shift();\n\n if (next) {\n // Perform the next unit of work;\n next[0](worker);\n } else if (this.#finishing) {\n // Shut down the worker (success)\n worker.postMessage(false);\n } else {\n // No pending work, idle the workers\n this.#idle.push(worker);\n }\n }\n\n /**\n * Checks out a currently available worker or waits for the next free worker.\n * @param allowCreate - If creating new workers is allowed (subject to maxSize)\n */\n public async checkoutWorkerAsync(allowCreate: boolean): Promise<Worker> {\n if (this.#error) {\n throw this.#error;\n }\n\n let worker: Worker | undefined = this.#idle.shift();\n if (!worker && allowCreate) {\n worker = this.#createWorker();\n }\n\n if (worker) {\n return worker;\n }\n\n return await new Promise((resolve: (worker: Worker) => void, reject: (error: Error) => void) => {\n this.#pending.push([resolve, reject]);\n });\n }\n\n /**\n * Creates a new worker if allowed by maxSize.\n */\n #createWorker(): Worker | undefined {\n if (this.#alive.length >= this.maxWorkers) {\n return;\n }\n\n const worker: Worker & {\n [WORKER_ID_SYMBOL]?: string;\n } = new Worker(this.#workerScript, {\n eval: false,\n workerData: this.#workerData,\n resourceLimits: this.#workerResourceLimits\n });\n\n const id: string = `${this.id}#${++this.#nextId}`;\n worker[WORKER_ID_SYMBOL] = id;\n\n this.#alive.push(worker);\n\n worker.on('error', (err) => {\n this.#onError(err);\n this.#destroyWorker(worker);\n });\n\n worker.once('exit', (exitCode) => {\n if (exitCode !== 0) {\n this.#onError(new Error(`Worker ${id} exited with code ${exitCode}`));\n }\n this.#destroyWorker(worker);\n });\n\n if (this.#prepare) {\n this.#prepare(worker);\n }\n\n return worker;\n }\n\n /**\n * Cleans up a worker\n */\n #destroyWorker(worker: Worker): void {\n const aliveIndex: number = this.#alive.indexOf(worker);\n if (aliveIndex >= 0) {\n this.#alive.splice(aliveIndex, 1);\n }\n\n const freeIndex: number = this.#idle.indexOf(worker);\n if (freeIndex >= 0) {\n this.#idle.splice(freeIndex, 1);\n }\n\n worker.unref();\n\n if (this.#onWorkerDestroyed) {\n this.#onWorkerDestroyed();\n }\n\n if (!this.#alive.length && !this.#error) {\n for (const [resolve] of this.#onComplete.splice(0)) {\n resolve();\n }\n }\n }\n\n /**\n * Notifies all pending callbacks that an error has occurred and switches this pool into error state.\n */\n #onError(error: Error): void {\n this.#error = error;\n\n for (const [, reject] of this.#pending.splice(0)) {\n reject(this.#error);\n }\n\n for (const [, reject] of this.#onComplete.splice(0)) {\n reject(this.#error);\n }\n }\n}\n"]}
|
package/lib-dts/WorkerPool.d.ts
CHANGED
|
@@ -44,20 +44,9 @@ export interface IWorkerPoolOptions {
|
|
|
44
44
|
* @internal
|
|
45
45
|
*/
|
|
46
46
|
export declare class WorkerPool {
|
|
47
|
+
#private;
|
|
47
48
|
id: string;
|
|
48
49
|
maxWorkers: number;
|
|
49
|
-
private readonly _alive;
|
|
50
|
-
private _error;
|
|
51
|
-
private _finishing;
|
|
52
|
-
private readonly _idle;
|
|
53
|
-
private _nextId;
|
|
54
|
-
private readonly _onComplete;
|
|
55
|
-
private readonly _onWorkerDestroyed;
|
|
56
|
-
private readonly _pending;
|
|
57
|
-
private readonly _prepare;
|
|
58
|
-
private readonly _workerData;
|
|
59
|
-
private readonly _workerScript;
|
|
60
|
-
private readonly _workerResourceLimits;
|
|
61
50
|
constructor(options: IWorkerPoolOptions);
|
|
62
51
|
/**
|
|
63
52
|
* Gets the count of active workers.
|
|
@@ -90,17 +79,5 @@ export declare class WorkerPool {
|
|
|
90
79
|
* @param allowCreate - If creating new workers is allowed (subject to maxSize)
|
|
91
80
|
*/
|
|
92
81
|
checkoutWorkerAsync(allowCreate: boolean): Promise<Worker>;
|
|
93
|
-
/**
|
|
94
|
-
* Creates a new worker if allowed by maxSize.
|
|
95
|
-
*/
|
|
96
|
-
private _createWorker;
|
|
97
|
-
/**
|
|
98
|
-
* Cleans up a worker
|
|
99
|
-
*/
|
|
100
|
-
private _destroyWorker;
|
|
101
|
-
/**
|
|
102
|
-
* Notifies all pending callbacks that an error has occurred and switches this pool into error state.
|
|
103
|
-
*/
|
|
104
|
-
private _onError;
|
|
105
82
|
}
|
|
106
83
|
//# sourceMappingURL=WorkerPool.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WorkerPool.d.ts","sourceRoot":"","sources":["../src/WorkerPool.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAElE;;;GAGG;AACH,eAAO,MAAM,gBAAgB,EAAE,OAAO,MAA2B,CAAC;AAElE;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,EAAE,EAAE,MAAM,CAAC;IACX;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,iBAAiB,CAAC,EAAE,MAAM,IAAI,CAAC;IAC/B;;OAEG;IACH,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;OAEG;IACH,gBAAgB,EAAE,MAAM,CAAC;IAEzB;;OAEG;IACH,oBAAoB,CAAC,EAAE,cAAc,CAAC;CACvC;AAED;;;;GAIG;AACH,qBAAa,UAAU
|
|
1
|
+
{"version":3,"file":"WorkerPool.d.ts","sourceRoot":"","sources":["../src/WorkerPool.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAElE;;;GAGG;AACH,eAAO,MAAM,gBAAgB,EAAE,OAAO,MAA2B,CAAC;AAElE;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,EAAE,EAAE,MAAM,CAAC;IACX;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,iBAAiB,CAAC,EAAE,MAAM,IAAI,CAAC;IAC/B;;OAEG;IACH,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;OAEG;IACH,gBAAgB,EAAE,MAAM,CAAC;IAEzB;;OAEG;IACH,oBAAoB,CAAC,EAAE,cAAc,CAAC;CACvC;AAED;;;;GAIG;AACH,qBAAa,UAAU;;IACd,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;gBAeP,OAAO,EAAE,kBAAkB;IA2B9C;;OAEG;IACI,cAAc,IAAI,MAAM;IAI/B;;OAEG;IACI,YAAY,IAAI,MAAM;IAI7B;;OAEG;IACI,YAAY,IAAI,MAAM;IAI7B;;;OAGG;IACU,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAqBzC;;OAEG;IACI,KAAK,IAAI,IAAI;IAKpB;;;OAGG;IACI,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAqB1C;;;OAGG;IACU,mBAAmB,CAAC,WAAW,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC;CAoGxE"}
|
package/lib-esm/WorkerPool.js
CHANGED
|
@@ -14,102 +14,102 @@ export const WORKER_ID_SYMBOL = Symbol('workerId');
|
|
|
14
14
|
export class WorkerPool {
|
|
15
15
|
id;
|
|
16
16
|
maxWorkers;
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
17
|
+
#alive;
|
|
18
|
+
#error;
|
|
19
|
+
#finishing;
|
|
20
|
+
#idle;
|
|
21
|
+
#nextId;
|
|
22
|
+
#onComplete;
|
|
23
|
+
#onWorkerDestroyed;
|
|
24
|
+
#pending;
|
|
25
|
+
#prepare;
|
|
26
|
+
#workerData;
|
|
27
|
+
#workerScript;
|
|
28
|
+
#workerResourceLimits;
|
|
29
29
|
constructor(options) {
|
|
30
30
|
const { id, maxWorkers, onWorkerDestroyed, prepareWorker, workerData, workerScriptPath, workerResourceLimits } = options;
|
|
31
31
|
this.id = id;
|
|
32
32
|
this.maxWorkers = maxWorkers;
|
|
33
|
-
this
|
|
34
|
-
this
|
|
35
|
-
this
|
|
36
|
-
this
|
|
37
|
-
this
|
|
38
|
-
this
|
|
39
|
-
this
|
|
40
|
-
this
|
|
41
|
-
this
|
|
42
|
-
this
|
|
43
|
-
this
|
|
44
|
-
this
|
|
33
|
+
this.#alive = [];
|
|
34
|
+
this.#error = undefined;
|
|
35
|
+
this.#finishing = false;
|
|
36
|
+
this.#idle = [];
|
|
37
|
+
this.#nextId = 0;
|
|
38
|
+
this.#onComplete = [];
|
|
39
|
+
this.#onWorkerDestroyed = onWorkerDestroyed;
|
|
40
|
+
this.#pending = [];
|
|
41
|
+
this.#prepare = prepareWorker;
|
|
42
|
+
this.#workerData = workerData;
|
|
43
|
+
this.#workerScript = workerScriptPath;
|
|
44
|
+
this.#workerResourceLimits = workerResourceLimits;
|
|
45
45
|
}
|
|
46
46
|
/**
|
|
47
47
|
* Gets the count of active workers.
|
|
48
48
|
*/
|
|
49
49
|
getActiveCount() {
|
|
50
|
-
return this.
|
|
50
|
+
return this.#alive.length - this.#idle.length;
|
|
51
51
|
}
|
|
52
52
|
/**
|
|
53
53
|
* Gets the count of idle workers.
|
|
54
54
|
*/
|
|
55
55
|
getIdleCount() {
|
|
56
|
-
return this.
|
|
56
|
+
return this.#idle.length;
|
|
57
57
|
}
|
|
58
58
|
/**
|
|
59
59
|
* Gets the count of live workers.
|
|
60
60
|
*/
|
|
61
61
|
getLiveCount() {
|
|
62
|
-
return this.
|
|
62
|
+
return this.#alive.length;
|
|
63
63
|
}
|
|
64
64
|
/**
|
|
65
65
|
* Tells the pool to shut down when all workers are done.
|
|
66
66
|
* Returns a promise that will be fulfilled if all workers finish successfully, or reject with the first error.
|
|
67
67
|
*/
|
|
68
68
|
async finishAsync() {
|
|
69
|
-
this
|
|
70
|
-
if (this
|
|
71
|
-
throw this
|
|
69
|
+
this.#finishing = true;
|
|
70
|
+
if (this.#error) {
|
|
71
|
+
throw this.#error;
|
|
72
72
|
}
|
|
73
|
-
if (!this.
|
|
73
|
+
if (!this.#alive.length) {
|
|
74
74
|
// The pool has no live workers, this is a no-op
|
|
75
75
|
return;
|
|
76
76
|
}
|
|
77
77
|
// Clean up all idle workers
|
|
78
|
-
for (const worker of this.
|
|
78
|
+
for (const worker of this.#idle.splice(0)) {
|
|
79
79
|
worker.postMessage(false);
|
|
80
80
|
}
|
|
81
81
|
// There are still active workers, wait for them to clean up.
|
|
82
|
-
await new Promise((resolve, reject) => this.
|
|
82
|
+
await new Promise((resolve, reject) => this.#onComplete.push([resolve, reject]));
|
|
83
83
|
}
|
|
84
84
|
/**
|
|
85
85
|
* Resets the pool and allows more work
|
|
86
86
|
*/
|
|
87
87
|
reset() {
|
|
88
|
-
this
|
|
89
|
-
this
|
|
88
|
+
this.#finishing = false;
|
|
89
|
+
this.#error = undefined;
|
|
90
90
|
}
|
|
91
91
|
/**
|
|
92
92
|
* Returns a worker to the pool. If the pool is finishing, deallocates the worker.
|
|
93
93
|
* @param worker - The worker to free
|
|
94
94
|
*/
|
|
95
95
|
checkinWorker(worker) {
|
|
96
|
-
if (this
|
|
96
|
+
if (this.#error) {
|
|
97
97
|
// Shut down the worker (failure)
|
|
98
98
|
worker.postMessage(false);
|
|
99
99
|
return;
|
|
100
100
|
}
|
|
101
|
-
const next = this.
|
|
101
|
+
const next = this.#pending.shift();
|
|
102
102
|
if (next) {
|
|
103
103
|
// Perform the next unit of work;
|
|
104
104
|
next[0](worker);
|
|
105
105
|
}
|
|
106
|
-
else if (this
|
|
106
|
+
else if (this.#finishing) {
|
|
107
107
|
// Shut down the worker (success)
|
|
108
108
|
worker.postMessage(false);
|
|
109
109
|
}
|
|
110
110
|
else {
|
|
111
111
|
// No pending work, idle the workers
|
|
112
|
-
this.
|
|
112
|
+
this.#idle.push(worker);
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
115
|
/**
|
|
@@ -117,68 +117,68 @@ export class WorkerPool {
|
|
|
117
117
|
* @param allowCreate - If creating new workers is allowed (subject to maxSize)
|
|
118
118
|
*/
|
|
119
119
|
async checkoutWorkerAsync(allowCreate) {
|
|
120
|
-
if (this
|
|
121
|
-
throw this
|
|
120
|
+
if (this.#error) {
|
|
121
|
+
throw this.#error;
|
|
122
122
|
}
|
|
123
|
-
let worker = this.
|
|
123
|
+
let worker = this.#idle.shift();
|
|
124
124
|
if (!worker && allowCreate) {
|
|
125
|
-
worker = this
|
|
125
|
+
worker = this.#createWorker();
|
|
126
126
|
}
|
|
127
127
|
if (worker) {
|
|
128
128
|
return worker;
|
|
129
129
|
}
|
|
130
130
|
return await new Promise((resolve, reject) => {
|
|
131
|
-
this.
|
|
131
|
+
this.#pending.push([resolve, reject]);
|
|
132
132
|
});
|
|
133
133
|
}
|
|
134
134
|
/**
|
|
135
135
|
* Creates a new worker if allowed by maxSize.
|
|
136
136
|
*/
|
|
137
|
-
|
|
138
|
-
if (this.
|
|
137
|
+
#createWorker() {
|
|
138
|
+
if (this.#alive.length >= this.maxWorkers) {
|
|
139
139
|
return;
|
|
140
140
|
}
|
|
141
|
-
const worker = new Worker(this
|
|
141
|
+
const worker = new Worker(this.#workerScript, {
|
|
142
142
|
eval: false,
|
|
143
|
-
workerData: this
|
|
144
|
-
resourceLimits: this
|
|
143
|
+
workerData: this.#workerData,
|
|
144
|
+
resourceLimits: this.#workerResourceLimits
|
|
145
145
|
});
|
|
146
|
-
const id = `${this.id}#${++this
|
|
146
|
+
const id = `${this.id}#${++this.#nextId}`;
|
|
147
147
|
worker[WORKER_ID_SYMBOL] = id;
|
|
148
|
-
this.
|
|
148
|
+
this.#alive.push(worker);
|
|
149
149
|
worker.on('error', (err) => {
|
|
150
|
-
this
|
|
151
|
-
this
|
|
150
|
+
this.#onError(err);
|
|
151
|
+
this.#destroyWorker(worker);
|
|
152
152
|
});
|
|
153
153
|
worker.once('exit', (exitCode) => {
|
|
154
154
|
if (exitCode !== 0) {
|
|
155
|
-
this
|
|
155
|
+
this.#onError(new Error(`Worker ${id} exited with code ${exitCode}`));
|
|
156
156
|
}
|
|
157
|
-
this
|
|
157
|
+
this.#destroyWorker(worker);
|
|
158
158
|
});
|
|
159
|
-
if (this
|
|
160
|
-
this
|
|
159
|
+
if (this.#prepare) {
|
|
160
|
+
this.#prepare(worker);
|
|
161
161
|
}
|
|
162
162
|
return worker;
|
|
163
163
|
}
|
|
164
164
|
/**
|
|
165
165
|
* Cleans up a worker
|
|
166
166
|
*/
|
|
167
|
-
|
|
168
|
-
const aliveIndex = this.
|
|
167
|
+
#destroyWorker(worker) {
|
|
168
|
+
const aliveIndex = this.#alive.indexOf(worker);
|
|
169
169
|
if (aliveIndex >= 0) {
|
|
170
|
-
this.
|
|
170
|
+
this.#alive.splice(aliveIndex, 1);
|
|
171
171
|
}
|
|
172
|
-
const freeIndex = this.
|
|
172
|
+
const freeIndex = this.#idle.indexOf(worker);
|
|
173
173
|
if (freeIndex >= 0) {
|
|
174
|
-
this.
|
|
174
|
+
this.#idle.splice(freeIndex, 1);
|
|
175
175
|
}
|
|
176
176
|
worker.unref();
|
|
177
|
-
if (this
|
|
178
|
-
this
|
|
177
|
+
if (this.#onWorkerDestroyed) {
|
|
178
|
+
this.#onWorkerDestroyed();
|
|
179
179
|
}
|
|
180
|
-
if (!this.
|
|
181
|
-
for (const [resolve] of this.
|
|
180
|
+
if (!this.#alive.length && !this.#error) {
|
|
181
|
+
for (const [resolve] of this.#onComplete.splice(0)) {
|
|
182
182
|
resolve();
|
|
183
183
|
}
|
|
184
184
|
}
|
|
@@ -186,13 +186,13 @@ export class WorkerPool {
|
|
|
186
186
|
/**
|
|
187
187
|
* Notifies all pending callbacks that an error has occurred and switches this pool into error state.
|
|
188
188
|
*/
|
|
189
|
-
|
|
190
|
-
this
|
|
191
|
-
for (const [, reject] of this.
|
|
192
|
-
reject(this
|
|
189
|
+
#onError(error) {
|
|
190
|
+
this.#error = error;
|
|
191
|
+
for (const [, reject] of this.#pending.splice(0)) {
|
|
192
|
+
reject(this.#error);
|
|
193
193
|
}
|
|
194
|
-
for (const [, reject] of this.
|
|
195
|
-
reject(this
|
|
194
|
+
for (const [, reject] of this.#onComplete.splice(0)) {
|
|
195
|
+
reject(this.#error);
|
|
196
196
|
}
|
|
197
197
|
}
|
|
198
198
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WorkerPool.js","sourceRoot":"","sources":["../src/WorkerPool.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { type ResourceLimits, Worker } from 'node:worker_threads';\n\n/**\n * Symbol to read the ID off of a worker\n * @internal\n */\nexport const WORKER_ID_SYMBOL: unique symbol = Symbol('workerId');\n\n/**\n * @internal\n */\nexport interface IWorkerPoolOptions {\n /**\n * Identifier for this pool, to assign to its workers for tracking\n */\n id: string;\n /**\n * Maximum number of concurrent workers this WorkerPool may spawn.\n */\n maxWorkers: number;\n /**\n * Optional callback invoked when a worker is destroyed.\n */\n onWorkerDestroyed?: () => void;\n /**\n * Optional callback invoked on a newly created worker.\n */\n prepareWorker?: (worker: Worker) => void;\n /**\n * Optional data to pass to workers when they are initialized.\n * Will be subjected to the Structured Clone algorithm.\n */\n workerData?: unknown;\n /**\n * Absolute path to the worker script.\n */\n workerScriptPath: string;\n\n /**\n * Optional resource limits for the workers.\n */\n workerResourceLimits?: ResourceLimits;\n}\n\n/**\n * Manages a pool of workers.\n * Workers will be shutdown by sending them the boolean value `false` in a postMessage.\n * @internal\n */\nexport class WorkerPool {\n public id: string;\n public maxWorkers: number;\n\n private readonly _alive: Worker[];\n private _error: Error | undefined;\n private _finishing: boolean;\n private readonly _idle: Worker[];\n private _nextId: number;\n private readonly _onComplete: [() => void, (error: Error) => void][];\n private readonly _onWorkerDestroyed: (() => void) | undefined;\n private readonly _pending: [(worker: Worker) => void, (error: Error) => void][];\n private readonly _prepare: ((worker: Worker) => void) | undefined;\n private readonly _workerData: unknown;\n private readonly _workerScript: string;\n private readonly _workerResourceLimits: ResourceLimits | undefined;\n\n public constructor(options: IWorkerPoolOptions) {\n const {\n id,\n maxWorkers,\n onWorkerDestroyed,\n prepareWorker,\n workerData,\n workerScriptPath,\n workerResourceLimits\n } = options;\n\n this.id = id;\n this.maxWorkers = maxWorkers;\n this._alive = [];\n this._error = undefined;\n this._finishing = false;\n this._idle = [];\n this._nextId = 0;\n this._onComplete = [];\n this._onWorkerDestroyed = onWorkerDestroyed;\n this._pending = [];\n this._prepare = prepareWorker;\n this._workerData = workerData;\n this._workerScript = workerScriptPath;\n this._workerResourceLimits = workerResourceLimits;\n }\n\n /**\n * Gets the count of active workers.\n */\n public getActiveCount(): number {\n return this._alive.length - this._idle.length;\n }\n\n /**\n * Gets the count of idle workers.\n */\n public getIdleCount(): number {\n return this._idle.length;\n }\n\n /**\n * Gets the count of live workers.\n */\n public getLiveCount(): number {\n return this._alive.length;\n }\n\n /**\n * Tells the pool to shut down when all workers are done.\n * Returns a promise that will be fulfilled if all workers finish successfully, or reject with the first error.\n */\n public async finishAsync(): Promise<void> {\n this._finishing = true;\n\n if (this._error) {\n throw this._error;\n }\n\n if (!this._alive.length) {\n // The pool has no live workers, this is a no-op\n return;\n }\n\n // Clean up all idle workers\n for (const worker of this._idle.splice(0)) {\n worker.postMessage(false);\n }\n\n // There are still active workers, wait for them to clean up.\n await new Promise<void>((resolve, reject) => this._onComplete.push([resolve, reject]));\n }\n\n /**\n * Resets the pool and allows more work\n */\n public reset(): void {\n this._finishing = false;\n this._error = undefined;\n }\n\n /**\n * Returns a worker to the pool. If the pool is finishing, deallocates the worker.\n * @param worker - The worker to free\n */\n public checkinWorker(worker: Worker): void {\n if (this._error) {\n // Shut down the worker (failure)\n worker.postMessage(false);\n return;\n }\n\n const next: [(worker: Worker) => void, unknown] | undefined = this._pending.shift();\n\n if (next) {\n // Perform the next unit of work;\n next[0](worker);\n } else if (this._finishing) {\n // Shut down the worker (success)\n worker.postMessage(false);\n } else {\n // No pending work, idle the workers\n this._idle.push(worker);\n }\n }\n\n /**\n * Checks out a currently available worker or waits for the next free worker.\n * @param allowCreate - If creating new workers is allowed (subject to maxSize)\n */\n public async checkoutWorkerAsync(allowCreate: boolean): Promise<Worker> {\n if (this._error) {\n throw this._error;\n }\n\n let worker: Worker | undefined = this._idle.shift();\n if (!worker && allowCreate) {\n worker = this._createWorker();\n }\n\n if (worker) {\n return worker;\n }\n\n return await new Promise((resolve: (worker: Worker) => void, reject: (error: Error) => void) => {\n this._pending.push([resolve, reject]);\n });\n }\n\n /**\n * Creates a new worker if allowed by maxSize.\n */\n private _createWorker(): Worker | undefined {\n if (this._alive.length >= this.maxWorkers) {\n return;\n }\n\n const worker: Worker & {\n [WORKER_ID_SYMBOL]?: string;\n } = new Worker(this._workerScript, {\n eval: false,\n workerData: this._workerData,\n resourceLimits: this._workerResourceLimits\n });\n\n const id: string = `${this.id}#${++this._nextId}`;\n worker[WORKER_ID_SYMBOL] = id;\n\n this._alive.push(worker);\n\n worker.on('error', (err) => {\n this._onError(err);\n this._destroyWorker(worker);\n });\n\n worker.once('exit', (exitCode) => {\n if (exitCode !== 0) {\n this._onError(new Error(`Worker ${id} exited with code ${exitCode}`));\n }\n this._destroyWorker(worker);\n });\n\n if (this._prepare) {\n this._prepare(worker);\n }\n\n return worker;\n }\n\n /**\n * Cleans up a worker\n */\n private _destroyWorker(worker: Worker): void {\n const aliveIndex: number = this._alive.indexOf(worker);\n if (aliveIndex >= 0) {\n this._alive.splice(aliveIndex, 1);\n }\n\n const freeIndex: number = this._idle.indexOf(worker);\n if (freeIndex >= 0) {\n this._idle.splice(freeIndex, 1);\n }\n\n worker.unref();\n\n if (this._onWorkerDestroyed) {\n this._onWorkerDestroyed();\n }\n\n if (!this._alive.length && !this._error) {\n for (const [resolve] of this._onComplete.splice(0)) {\n resolve();\n }\n }\n }\n\n /**\n * Notifies all pending callbacks that an error has occurred and switches this pool into error state.\n */\n private _onError(error: Error): void {\n this._error = error;\n\n for (const [, reject] of this._pending.splice(0)) {\n reject(this._error);\n }\n\n for (const [, reject] of this._onComplete.splice(0)) {\n reject(this._error);\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"WorkerPool.js","sourceRoot":"","sources":["../src/WorkerPool.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\nimport { type ResourceLimits, Worker } from 'node:worker_threads';\n\n/**\n * Symbol to read the ID off of a worker\n * @internal\n */\nexport const WORKER_ID_SYMBOL: unique symbol = Symbol('workerId');\n\n/**\n * @internal\n */\nexport interface IWorkerPoolOptions {\n /**\n * Identifier for this pool, to assign to its workers for tracking\n */\n id: string;\n /**\n * Maximum number of concurrent workers this WorkerPool may spawn.\n */\n maxWorkers: number;\n /**\n * Optional callback invoked when a worker is destroyed.\n */\n onWorkerDestroyed?: () => void;\n /**\n * Optional callback invoked on a newly created worker.\n */\n prepareWorker?: (worker: Worker) => void;\n /**\n * Optional data to pass to workers when they are initialized.\n * Will be subjected to the Structured Clone algorithm.\n */\n workerData?: unknown;\n /**\n * Absolute path to the worker script.\n */\n workerScriptPath: string;\n\n /**\n * Optional resource limits for the workers.\n */\n workerResourceLimits?: ResourceLimits;\n}\n\n/**\n * Manages a pool of workers.\n * Workers will be shutdown by sending them the boolean value `false` in a postMessage.\n * @internal\n */\nexport class WorkerPool {\n public id: string;\n public maxWorkers: number;\n\n readonly #alive: Worker[];\n #error: Error | undefined;\n #finishing: boolean;\n readonly #idle: Worker[];\n #nextId: number;\n readonly #onComplete: [() => void, (error: Error) => void][];\n readonly #onWorkerDestroyed: (() => void) | undefined;\n readonly #pending: [(worker: Worker) => void, (error: Error) => void][];\n readonly #prepare: ((worker: Worker) => void) | undefined;\n readonly #workerData: unknown;\n readonly #workerScript: string;\n readonly #workerResourceLimits: ResourceLimits | undefined;\n\n public constructor(options: IWorkerPoolOptions) {\n const {\n id,\n maxWorkers,\n onWorkerDestroyed,\n prepareWorker,\n workerData,\n workerScriptPath,\n workerResourceLimits\n } = options;\n\n this.id = id;\n this.maxWorkers = maxWorkers;\n this.#alive = [];\n this.#error = undefined;\n this.#finishing = false;\n this.#idle = [];\n this.#nextId = 0;\n this.#onComplete = [];\n this.#onWorkerDestroyed = onWorkerDestroyed;\n this.#pending = [];\n this.#prepare = prepareWorker;\n this.#workerData = workerData;\n this.#workerScript = workerScriptPath;\n this.#workerResourceLimits = workerResourceLimits;\n }\n\n /**\n * Gets the count of active workers.\n */\n public getActiveCount(): number {\n return this.#alive.length - this.#idle.length;\n }\n\n /**\n * Gets the count of idle workers.\n */\n public getIdleCount(): number {\n return this.#idle.length;\n }\n\n /**\n * Gets the count of live workers.\n */\n public getLiveCount(): number {\n return this.#alive.length;\n }\n\n /**\n * Tells the pool to shut down when all workers are done.\n * Returns a promise that will be fulfilled if all workers finish successfully, or reject with the first error.\n */\n public async finishAsync(): Promise<void> {\n this.#finishing = true;\n\n if (this.#error) {\n throw this.#error;\n }\n\n if (!this.#alive.length) {\n // The pool has no live workers, this is a no-op\n return;\n }\n\n // Clean up all idle workers\n for (const worker of this.#idle.splice(0)) {\n worker.postMessage(false);\n }\n\n // There are still active workers, wait for them to clean up.\n await new Promise<void>((resolve, reject) => this.#onComplete.push([resolve, reject]));\n }\n\n /**\n * Resets the pool and allows more work\n */\n public reset(): void {\n this.#finishing = false;\n this.#error = undefined;\n }\n\n /**\n * Returns a worker to the pool. If the pool is finishing, deallocates the worker.\n * @param worker - The worker to free\n */\n public checkinWorker(worker: Worker): void {\n if (this.#error) {\n // Shut down the worker (failure)\n worker.postMessage(false);\n return;\n }\n\n const next: [(worker: Worker) => void, unknown] | undefined = this.#pending.shift();\n\n if (next) {\n // Perform the next unit of work;\n next[0](worker);\n } else if (this.#finishing) {\n // Shut down the worker (success)\n worker.postMessage(false);\n } else {\n // No pending work, idle the workers\n this.#idle.push(worker);\n }\n }\n\n /**\n * Checks out a currently available worker or waits for the next free worker.\n * @param allowCreate - If creating new workers is allowed (subject to maxSize)\n */\n public async checkoutWorkerAsync(allowCreate: boolean): Promise<Worker> {\n if (this.#error) {\n throw this.#error;\n }\n\n let worker: Worker | undefined = this.#idle.shift();\n if (!worker && allowCreate) {\n worker = this.#createWorker();\n }\n\n if (worker) {\n return worker;\n }\n\n return await new Promise((resolve: (worker: Worker) => void, reject: (error: Error) => void) => {\n this.#pending.push([resolve, reject]);\n });\n }\n\n /**\n * Creates a new worker if allowed by maxSize.\n */\n #createWorker(): Worker | undefined {\n if (this.#alive.length >= this.maxWorkers) {\n return;\n }\n\n const worker: Worker & {\n [WORKER_ID_SYMBOL]?: string;\n } = new Worker(this.#workerScript, {\n eval: false,\n workerData: this.#workerData,\n resourceLimits: this.#workerResourceLimits\n });\n\n const id: string = `${this.id}#${++this.#nextId}`;\n worker[WORKER_ID_SYMBOL] = id;\n\n this.#alive.push(worker);\n\n worker.on('error', (err) => {\n this.#onError(err);\n this.#destroyWorker(worker);\n });\n\n worker.once('exit', (exitCode) => {\n if (exitCode !== 0) {\n this.#onError(new Error(`Worker ${id} exited with code ${exitCode}`));\n }\n this.#destroyWorker(worker);\n });\n\n if (this.#prepare) {\n this.#prepare(worker);\n }\n\n return worker;\n }\n\n /**\n * Cleans up a worker\n */\n #destroyWorker(worker: Worker): void {\n const aliveIndex: number = this.#alive.indexOf(worker);\n if (aliveIndex >= 0) {\n this.#alive.splice(aliveIndex, 1);\n }\n\n const freeIndex: number = this.#idle.indexOf(worker);\n if (freeIndex >= 0) {\n this.#idle.splice(freeIndex, 1);\n }\n\n worker.unref();\n\n if (this.#onWorkerDestroyed) {\n this.#onWorkerDestroyed();\n }\n\n if (!this.#alive.length && !this.#error) {\n for (const [resolve] of this.#onComplete.splice(0)) {\n resolve();\n }\n }\n }\n\n /**\n * Notifies all pending callbacks that an error has occurred and switches this pool into error state.\n */\n #onError(error: Error): void {\n this.#error = error;\n\n for (const [, reject] of this.#pending.splice(0)) {\n reject(this.#error);\n }\n\n for (const [, reject] of this.#onComplete.splice(0)) {\n reject(this.#error);\n }\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rushstack/worker-pool",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.26",
|
|
4
4
|
"description": "Lightweight worker pool using NodeJS worker_threads",
|
|
5
5
|
"main": "./lib-commonjs/index.js",
|
|
6
6
|
"module": "./lib-esm/index.js",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"eslint": "~9.37.0",
|
|
41
|
-
"@rushstack/heft": "1.2.
|
|
41
|
+
"@rushstack/heft": "1.2.26",
|
|
42
42
|
"local-node-rig": "1.0.0"
|
|
43
43
|
},
|
|
44
44
|
"peerDependencies": {
|