@rushstack/worker-pool 0.7.25 → 0.7.27

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 CHANGED
@@ -1,6 +1,35 @@
1
1
  {
2
2
  "name": "@rushstack/worker-pool",
3
3
  "entries": [
4
+ {
5
+ "version": "0.7.27",
6
+ "tag": "@rushstack/worker-pool_v0.7.27",
7
+ "date": "Mon, 14 Sep 2026 22:42:32 GMT",
8
+ "comments": {
9
+ "none": [
10
+ {
11
+ "comment": "Use ECMAScript private syntax for internal class members."
12
+ }
13
+ ],
14
+ "dependency": [
15
+ {
16
+ "comment": "Updating dependency \"@rushstack/heft\" to `1.3.0`"
17
+ }
18
+ ]
19
+ }
20
+ },
21
+ {
22
+ "version": "0.7.26",
23
+ "tag": "@rushstack/worker-pool_v0.7.26",
24
+ "date": "Sat, 05 Sep 2026 00:15:08 GMT",
25
+ "comments": {
26
+ "dependency": [
27
+ {
28
+ "comment": "Updating dependency \"@rushstack/heft\" to `1.2.26`"
29
+ }
30
+ ]
31
+ }
32
+ },
4
33
  {
5
34
  "version": "0.7.25",
6
35
  "tag": "@rushstack/worker-pool_v0.7.25",
package/CHANGELOG.md CHANGED
@@ -1,6 +1,16 @@
1
1
  # Change Log - @rushstack/worker-pool
2
2
 
3
- This log was last generated on Fri, 21 Aug 2026 15:16:35 GMT and should not be manually modified.
3
+ This log was last generated on Mon, 14 Sep 2026 22:42:32 GMT and should not be manually modified.
4
+
5
+ ## 0.7.27
6
+ Mon, 14 Sep 2026 22:42:32 GMT
7
+
8
+ _Version update only_
9
+
10
+ ## 0.7.26
11
+ Sat, 05 Sep 2026 00:15:08 GMT
12
+
13
+ _Version update only_
4
14
 
5
15
  ## 0.7.25
6
16
  Fri, 21 Aug 2026 15:16:35 GMT
@@ -5,7 +5,7 @@
5
5
  "toolPackages": [
6
6
  {
7
7
  "packageName": "@microsoft/api-extractor",
8
- "packageVersion": "7.58.13"
8
+ "packageVersion": "7.59.1"
9
9
  }
10
10
  ]
11
11
  }
@@ -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
- _alive;
21
- _error;
22
- _finishing;
23
- _idle;
24
- _nextId;
25
- _onComplete;
26
- _onWorkerDestroyed;
27
- _pending;
28
- _prepare;
29
- _workerData;
30
- _workerScript;
31
- _workerResourceLimits;
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._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;
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._alive.length - this._idle.length;
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._idle.length;
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._alive.length;
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._finishing = true;
73
- if (this._error) {
74
- throw this._error;
72
+ this.#finishing = true;
73
+ if (this.#error) {
74
+ throw this.#error;
75
75
  }
76
- if (!this._alive.length) {
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._idle.splice(0)) {
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._onComplete.push([resolve, reject]));
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._finishing = false;
92
- this._error = undefined;
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._error) {
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._pending.shift();
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._finishing) {
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._idle.push(worker);
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._error) {
124
- throw this._error;
123
+ if (this.#error) {
124
+ throw this.#error;
125
125
  }
126
- let worker = this._idle.shift();
126
+ let worker = this.#idle.shift();
127
127
  if (!worker && allowCreate) {
128
- worker = this._createWorker();
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._pending.push([resolve, reject]);
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
- _createWorker() {
141
- if (this._alive.length >= this.maxWorkers) {
140
+ #createWorker() {
141
+ if (this.#alive.length >= this.maxWorkers) {
142
142
  return;
143
143
  }
144
- const worker = new node_worker_threads_1.Worker(this._workerScript, {
144
+ const worker = new node_worker_threads_1.Worker(this.#workerScript, {
145
145
  eval: false,
146
- workerData: this._workerData,
147
- resourceLimits: this._workerResourceLimits
146
+ workerData: this.#workerData,
147
+ resourceLimits: this.#workerResourceLimits
148
148
  });
149
- const id = `${this.id}#${++this._nextId}`;
149
+ const id = `${this.id}#${++this.#nextId}`;
150
150
  worker[exports.WORKER_ID_SYMBOL] = id;
151
- this._alive.push(worker);
151
+ this.#alive.push(worker);
152
152
  worker.on('error', (err) => {
153
- this._onError(err);
154
- this._destroyWorker(worker);
153
+ this.#onError(err);
154
+ this.#destroyWorker(worker);
155
155
  });
156
156
  worker.once('exit', (exitCode) => {
157
157
  if (exitCode !== 0) {
158
- this._onError(new Error(`Worker ${id} exited with code ${exitCode}`));
158
+ this.#onError(new Error(`Worker ${id} exited with code ${exitCode}`));
159
159
  }
160
- this._destroyWorker(worker);
160
+ this.#destroyWorker(worker);
161
161
  });
162
- if (this._prepare) {
163
- this._prepare(worker);
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
- _destroyWorker(worker) {
171
- const aliveIndex = this._alive.indexOf(worker);
170
+ #destroyWorker(worker) {
171
+ const aliveIndex = this.#alive.indexOf(worker);
172
172
  if (aliveIndex >= 0) {
173
- this._alive.splice(aliveIndex, 1);
173
+ this.#alive.splice(aliveIndex, 1);
174
174
  }
175
- const freeIndex = this._idle.indexOf(worker);
175
+ const freeIndex = this.#idle.indexOf(worker);
176
176
  if (freeIndex >= 0) {
177
- this._idle.splice(freeIndex, 1);
177
+ this.#idle.splice(freeIndex, 1);
178
178
  }
179
179
  worker.unref();
180
- if (this._onWorkerDestroyed) {
181
- this._onWorkerDestroyed();
180
+ if (this.#onWorkerDestroyed) {
181
+ this.#onWorkerDestroyed();
182
182
  }
183
- if (!this._alive.length && !this._error) {
184
- for (const [resolve] of this._onComplete.splice(0)) {
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
- _onError(error) {
193
- this._error = error;
194
- for (const [, reject] of this._pending.splice(0)) {
195
- reject(this._error);
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._onComplete.splice(0)) {
198
- reject(this._error);
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":";AAAA,4FAA4F;AAC5F,2DAA2D;;;AAE3D,6DAAkE;AAElE;;;GAGG;AACU,QAAA,gBAAgB,GAAkB,MAAM,CAAC,UAAU,CAAC,CAAC;AAsClE;;;;GAIG;AACH,MAAa,UAAU;IACd,EAAE,CAAS;IACX,UAAU,CAAS;IAET,MAAM,CAAW;IAC1B,MAAM,CAAoB;IAC1B,UAAU,CAAU;IACX,KAAK,CAAW;IACzB,OAAO,CAAS;IACP,WAAW,CAAyC;IACpD,kBAAkB,CAA2B;IAC7C,QAAQ,CAAuD;IAC/D,QAAQ,CAAyC;IACjD,WAAW,CAAU;IACrB,aAAa,CAAS;IACtB,qBAAqB,CAA6B;IAEnE,YAAmB,OAA2B;QAC5C,MAAM,EACJ,EAAE,EACF,UAAU,EACV,iBAAiB,EACjB,aAAa,EACb,UAAU,EACV,gBAAgB,EAChB,oBAAoB,EACrB,GAAG,OAAO,CAAC;QAEZ,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;QACjB,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC;QACxB,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;QACxB,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;QAChB,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;QACjB,IAAI,CAAC,WAAW,GAAG,EAAE,CAAC;QACtB,IAAI,CAAC,kBAAkB,GAAG,iBAAiB,CAAC;QAC5C,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;QACnB,IAAI,CAAC,QAAQ,GAAG,aAAa,CAAC;QAC9B,IAAI,CAAC,WAAW,GAAG,UAAU,CAAC;QAC9B,IAAI,CAAC,aAAa,GAAG,gBAAgB,CAAC;QACtC,IAAI,CAAC,qBAAqB,GAAG,oBAAoB,CAAC;IACpD,CAAC;IAED;;OAEG;IACI,cAAc;QACnB,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;IAChD,CAAC;IAED;;OAEG;IACI,YAAY;QACjB,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;IAC3B,CAAC;IAED;;OAEG;IACI,YAAY;QACjB,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;IAC5B,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,WAAW;QACtB,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QAEvB,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,MAAM,IAAI,CAAC,MAAM,CAAC;QACpB,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;YACxB,gDAAgD;YAChD,OAAO;QACT,CAAC;QAED,4BAA4B;QAC5B,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;YAC1C,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QAC5B,CAAC;QAED,6DAA6D;QAC7D,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;IACzF,CAAC;IAED;;OAEG;IACI,KAAK;QACV,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;QACxB,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC;IAC1B,CAAC;IAED;;;OAGG;IACI,aAAa,CAAC,MAAc;QACjC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,iCAAiC;YACjC,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;YAC1B,OAAO;QACT,CAAC;QAED,MAAM,IAAI,GAAoD,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QAEpF,IAAI,IAAI,EAAE,CAAC;YACT,iCAAiC;YACjC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QAClB,CAAC;aAAM,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YAC3B,iCAAiC;YACjC,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QAC5B,CAAC;aAAM,CAAC;YACN,oCAAoC;YACpC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,mBAAmB,CAAC,WAAoB;QACnD,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,MAAM,IAAI,CAAC,MAAM,CAAC;QACpB,CAAC;QAED,IAAI,MAAM,GAAuB,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACpD,IAAI,CAAC,MAAM,IAAI,WAAW,EAAE,CAAC;YAC3B,MAAM,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;QAChC,CAAC;QAED,IAAI,MAAM,EAAE,CAAC;YACX,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,OAAO,MAAM,IAAI,OAAO,CAAC,CAAC,OAAiC,EAAE,MAA8B,EAAE,EAAE;YAC7F,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;QACxC,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACK,aAAa;QACnB,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YAC1C,OAAO;QACT,CAAC;QAED,MAAM,MAAM,GAER,IAAI,4BAAM,CAAC,IAAI,CAAC,aAAa,EAAE;YACjC,IAAI,EAAE,KAAK;YACX,UAAU,EAAE,IAAI,CAAC,WAAW;YAC5B,cAAc,EAAE,IAAI,CAAC,qBAAqB;SAC3C,CAAC,CAAC;QAEH,MAAM,EAAE,GAAW,GAAG,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC;QAClD,MAAM,CAAC,wBAAgB,CAAC,GAAG,EAAE,CAAC;QAE9B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAEzB,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACzB,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;YACnB,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;QAC9B,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE;YAC/B,IAAI,QAAQ,KAAK,CAAC,EAAE,CAAC;gBACnB,IAAI,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC,UAAU,EAAE,qBAAqB,QAAQ,EAAE,CAAC,CAAC,CAAC;YACxE,CAAC;YACD,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;QAC9B,CAAC,CAAC,CAAC;QAEH,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACxB,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;OAEG;IACK,cAAc,CAAC,MAAc;QACnC,MAAM,UAAU,GAAW,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACvD,IAAI,UAAU,IAAI,CAAC,EAAE,CAAC;YACpB,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;QACpC,CAAC;QAED,MAAM,SAAS,GAAW,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACrD,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;YACnB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;QAClC,CAAC;QAED,MAAM,CAAC,KAAK,EAAE,CAAC;QAEf,IAAI,IAAI,CAAC,kBAAkB,EAAE,CAAC;YAC5B,IAAI,CAAC,kBAAkB,EAAE,CAAC;QAC5B,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACxC,KAAK,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;gBACnD,OAAO,EAAE,CAAC;YACZ,CAAC;QACH,CAAC;IACH,CAAC;IAED;;OAEG;IACK,QAAQ,CAAC,KAAY;QAC3B,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QAEpB,KAAK,MAAM,CAAC,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;YACjD,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACtB,CAAC;QAED,KAAK,MAAM,CAAC,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;YACpD,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;CACF;AAnOD,gCAmOC","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"]}
@@ -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;IACd,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IAE1B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAW;IAClC,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,UAAU,CAAU;IAC5B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAW;IACjC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAyC;IACrE,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAA2B;IAC9D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAuD;IAChF,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAyC;IAClE,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAU;IACtC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAA6B;gBAEhD,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;IAmBvE;;OAEG;IACH,OAAO,CAAC,aAAa;IAqCrB;;OAEG;IACH,OAAO,CAAC,cAAc;IAwBtB;;OAEG;IACH,OAAO,CAAC,QAAQ;CAWjB"}
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"}
@@ -14,102 +14,102 @@ export const WORKER_ID_SYMBOL = Symbol('workerId');
14
14
  export class WorkerPool {
15
15
  id;
16
16
  maxWorkers;
17
- _alive;
18
- _error;
19
- _finishing;
20
- _idle;
21
- _nextId;
22
- _onComplete;
23
- _onWorkerDestroyed;
24
- _pending;
25
- _prepare;
26
- _workerData;
27
- _workerScript;
28
- _workerResourceLimits;
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._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;
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._alive.length - this._idle.length;
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._idle.length;
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._alive.length;
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._finishing = true;
70
- if (this._error) {
71
- throw this._error;
69
+ this.#finishing = true;
70
+ if (this.#error) {
71
+ throw this.#error;
72
72
  }
73
- if (!this._alive.length) {
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._idle.splice(0)) {
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._onComplete.push([resolve, reject]));
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._finishing = false;
89
- this._error = undefined;
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._error) {
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._pending.shift();
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._finishing) {
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._idle.push(worker);
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._error) {
121
- throw this._error;
120
+ if (this.#error) {
121
+ throw this.#error;
122
122
  }
123
- let worker = this._idle.shift();
123
+ let worker = this.#idle.shift();
124
124
  if (!worker && allowCreate) {
125
- worker = this._createWorker();
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._pending.push([resolve, reject]);
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
- _createWorker() {
138
- if (this._alive.length >= this.maxWorkers) {
137
+ #createWorker() {
138
+ if (this.#alive.length >= this.maxWorkers) {
139
139
  return;
140
140
  }
141
- const worker = new Worker(this._workerScript, {
141
+ const worker = new Worker(this.#workerScript, {
142
142
  eval: false,
143
- workerData: this._workerData,
144
- resourceLimits: this._workerResourceLimits
143
+ workerData: this.#workerData,
144
+ resourceLimits: this.#workerResourceLimits
145
145
  });
146
- const id = `${this.id}#${++this._nextId}`;
146
+ const id = `${this.id}#${++this.#nextId}`;
147
147
  worker[WORKER_ID_SYMBOL] = id;
148
- this._alive.push(worker);
148
+ this.#alive.push(worker);
149
149
  worker.on('error', (err) => {
150
- this._onError(err);
151
- this._destroyWorker(worker);
150
+ this.#onError(err);
151
+ this.#destroyWorker(worker);
152
152
  });
153
153
  worker.once('exit', (exitCode) => {
154
154
  if (exitCode !== 0) {
155
- this._onError(new Error(`Worker ${id} exited with code ${exitCode}`));
155
+ this.#onError(new Error(`Worker ${id} exited with code ${exitCode}`));
156
156
  }
157
- this._destroyWorker(worker);
157
+ this.#destroyWorker(worker);
158
158
  });
159
- if (this._prepare) {
160
- this._prepare(worker);
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
- _destroyWorker(worker) {
168
- const aliveIndex = this._alive.indexOf(worker);
167
+ #destroyWorker(worker) {
168
+ const aliveIndex = this.#alive.indexOf(worker);
169
169
  if (aliveIndex >= 0) {
170
- this._alive.splice(aliveIndex, 1);
170
+ this.#alive.splice(aliveIndex, 1);
171
171
  }
172
- const freeIndex = this._idle.indexOf(worker);
172
+ const freeIndex = this.#idle.indexOf(worker);
173
173
  if (freeIndex >= 0) {
174
- this._idle.splice(freeIndex, 1);
174
+ this.#idle.splice(freeIndex, 1);
175
175
  }
176
176
  worker.unref();
177
- if (this._onWorkerDestroyed) {
178
- this._onWorkerDestroyed();
177
+ if (this.#onWorkerDestroyed) {
178
+ this.#onWorkerDestroyed();
179
179
  }
180
- if (!this._alive.length && !this._error) {
181
- for (const [resolve] of this._onComplete.splice(0)) {
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
- _onError(error) {
190
- this._error = error;
191
- for (const [, reject] of this._pending.splice(0)) {
192
- reject(this._error);
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._onComplete.splice(0)) {
195
- reject(this._error);
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.25",
3
+ "version": "0.7.27",
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,8 +38,8 @@
38
38
  },
39
39
  "devDependencies": {
40
40
  "eslint": "~9.37.0",
41
- "local-node-rig": "1.0.0",
42
- "@rushstack/heft": "1.2.25"
41
+ "@rushstack/heft": "1.3.0",
42
+ "local-node-rig": "1.0.0"
43
43
  },
44
44
  "peerDependencies": {
45
45
  "@types/node": "*"
@@ -53,6 +53,7 @@
53
53
  "scripts": {
54
54
  "build": "heft build --clean",
55
55
  "_phase:build": "heft run --only build -- --clean",
56
+ "_phase:pack": "rush-pnpm pack",
56
57
  "_phase:test": "heft run --only test -- --clean"
57
58
  }
58
59
  }