@rushstack/worker-pool
Advanced tools
@@ -8,5 +8,5 @@ // This file is read by tools that parse documentation comments conforming to the TSDoc standard. | ||
| "packageName": "@microsoft/api-extractor", | ||
| "packageVersion": "7.38.0" | ||
| "packageVersion": "7.38.1" | ||
| } | ||
| ] | ||
| } |
+1
-1
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D;;;AAS3D,2CAA4D;AAAnD,8GAAA,gBAAgB,OAAA;AAAE,wGAAA,UAAU,OAAA","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\r\n// See LICENSE in the project root for license information.\r\n\r\n/**\r\n * A lightweight worker pool implementation using the NodeJS `worker_threads` API.\r\n *\r\n * @packageDocumentation\r\n */\r\n\r\nexport type { IWorkerPoolOptions } from './WorkerPool';\r\nexport { WORKER_ID_SYMBOL, WorkerPool } from './WorkerPool';\r\n"]} | ||
| {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,4FAA4F;AAC5F,2DAA2D;;;AAS3D,2CAA4D;AAAnD,8GAAA,gBAAgB,OAAA;AAAE,wGAAA,UAAU,OAAA","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n// See LICENSE in the project root for license information.\n\n/**\n * A lightweight worker pool implementation using the NodeJS `worker_threads` API.\n *\n * @packageDocumentation\n */\n\nexport type { IWorkerPoolOptions } from './WorkerPool';\nexport { WORKER_ID_SYMBOL, WorkerPool } from './WorkerPool';\n"]} |
@@ -1,1 +0,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.\r\n// See LICENSE in the project root for license information.\r\n\r\nimport { Worker } from 'worker_threads';\r\n\r\n/**\r\n * Symbol to read the ID off of a worker\r\n * @internal\r\n */\r\nexport const WORKER_ID_SYMBOL: unique symbol = Symbol('workerId');\r\n\r\n/**\r\n * @internal\r\n */\r\nexport interface IWorkerPoolOptions {\r\n /**\r\n * Identifier for this pool, to assign to its workers for tracking\r\n */\r\n id: string;\r\n /**\r\n * Maximum number of concurrent workers this WorkerPool may spawn.\r\n */\r\n maxWorkers: number;\r\n /**\r\n * Optional callback invoked when a worker is destroyed.\r\n */\r\n onWorkerDestroyed?: () => void;\r\n /**\r\n * Optional callback invoked on a newly created worker.\r\n */\r\n prepareWorker?: (worker: Worker) => void;\r\n /**\r\n * Optional data to pass to workers when they are initialized.\r\n * Will be subjected to the Structured Clone algorithm.\r\n */\r\n workerData?: unknown;\r\n /**\r\n * Absolute path to the worker script.\r\n */\r\n workerScriptPath: string;\r\n}\r\n\r\n/**\r\n * Manages a pool of workers.\r\n * Workers will be shutdown by sending them the boolean value `false` in a postMessage.\r\n * @internal\r\n */\r\nexport class WorkerPool {\r\n public id: string;\r\n public maxWorkers: number;\r\n\r\n private readonly _alive: Worker[];\r\n private _error: Error | undefined;\r\n private _finishing: boolean;\r\n private readonly _idle: Worker[];\r\n private _nextId: number;\r\n private readonly _onComplete: [() => void, (error: Error) => void][];\r\n private readonly _onWorkerDestroyed: (() => void) | undefined;\r\n private readonly _pending: [(worker: Worker) => void, (error: Error) => void][];\r\n private readonly _prepare: ((worker: Worker) => void) | undefined;\r\n private readonly _workerData: unknown;\r\n private readonly _workerScript: string;\r\n\r\n public constructor(options: IWorkerPoolOptions) {\r\n const { id, maxWorkers, onWorkerDestroyed, prepareWorker, workerData, workerScriptPath } = options;\r\n\r\n this.id = id;\r\n this.maxWorkers = maxWorkers;\r\n this._alive = [];\r\n this._error = undefined;\r\n this._finishing = false;\r\n this._idle = [];\r\n this._nextId = 0;\r\n this._onComplete = [];\r\n this._onWorkerDestroyed = onWorkerDestroyed;\r\n this._pending = [];\r\n this._prepare = prepareWorker;\r\n this._workerData = workerData;\r\n this._workerScript = workerScriptPath;\r\n }\r\n\r\n /**\r\n * Gets the count of active workers.\r\n */\r\n public getActiveCount(): number {\r\n return this._alive.length - this._idle.length;\r\n }\r\n\r\n /**\r\n * Gets the count of idle workers.\r\n */\r\n public getIdleCount(): number {\r\n return this._idle.length;\r\n }\r\n\r\n /**\r\n * Gets the count of live workers.\r\n */\r\n public getLiveCount(): number {\r\n return this._alive.length;\r\n }\r\n\r\n /**\r\n * Tells the pool to shut down when all workers are done.\r\n * Returns a promise that will be fulfilled if all workers finish successfully, or reject with the first error.\r\n */\r\n public async finishAsync(): Promise<void> {\r\n this._finishing = true;\r\n\r\n if (this._error) {\r\n throw this._error;\r\n }\r\n\r\n if (!this._alive.length) {\r\n // The pool has no live workers, this is a no-op\r\n return;\r\n }\r\n\r\n // Clean up all idle workers\r\n for (const worker of this._idle.splice(0)) {\r\n worker.postMessage(false);\r\n }\r\n\r\n // There are still active workers, wait for them to clean up.\r\n await new Promise<void>((resolve, reject) => this._onComplete.push([resolve, reject]));\r\n }\r\n\r\n /**\r\n * Resets the pool and allows more work\r\n */\r\n public reset(): void {\r\n this._finishing = false;\r\n this._error = undefined;\r\n }\r\n\r\n /**\r\n * Returns a worker to the pool. If the pool is finishing, deallocates the worker.\r\n * @param worker - The worker to free\r\n */\r\n public checkinWorker(worker: Worker): void {\r\n if (this._error) {\r\n // Shut down the worker (failure)\r\n worker.postMessage(false);\r\n return;\r\n }\r\n\r\n const next: [(worker: Worker) => void, unknown] | undefined = this._pending.shift();\r\n\r\n if (next) {\r\n // Perform the next unit of work;\r\n next[0](worker);\r\n } else if (this._finishing) {\r\n // Shut down the worker (success)\r\n worker.postMessage(false);\r\n } else {\r\n // No pending work, idle the workers\r\n this._idle.push(worker);\r\n }\r\n }\r\n\r\n /**\r\n * Checks out a currently available worker or waits for the next free worker.\r\n * @param allowCreate - If creating new workers is allowed (subject to maxSize)\r\n */\r\n public async checkoutWorkerAsync(allowCreate: boolean): Promise<Worker> {\r\n if (this._error) {\r\n throw this._error;\r\n }\r\n\r\n let worker: Worker | undefined = this._idle.shift();\r\n if (!worker && allowCreate) {\r\n worker = this._createWorker();\r\n }\r\n\r\n if (worker) {\r\n return worker;\r\n }\r\n\r\n return await new Promise((resolve: (worker: Worker) => void, reject: (error: Error) => void) => {\r\n this._pending.push([resolve, reject]);\r\n });\r\n }\r\n\r\n /**\r\n * Creates a new worker if allowed by maxSize.\r\n */\r\n private _createWorker(): Worker | undefined {\r\n if (this._alive.length >= this.maxWorkers) {\r\n return;\r\n }\r\n\r\n const worker: Worker & {\r\n [WORKER_ID_SYMBOL]?: string;\r\n } = new Worker(this._workerScript, {\r\n eval: false,\r\n workerData: this._workerData\r\n });\r\n\r\n const id: string = `${this.id}#${++this._nextId}`;\r\n worker[WORKER_ID_SYMBOL] = id;\r\n\r\n this._alive.push(worker);\r\n\r\n worker.on('error', (err) => {\r\n this._onError(err);\r\n this._destroyWorker(worker);\r\n });\r\n\r\n worker.on('exit', (exitCode) => {\r\n if (exitCode !== 0) {\r\n this._onError(new Error(`Worker ${id} exited with code ${exitCode}`));\r\n }\r\n this._destroyWorker(worker);\r\n });\r\n\r\n if (this._prepare) {\r\n this._prepare(worker);\r\n }\r\n\r\n return worker;\r\n }\r\n\r\n /**\r\n * Cleans up a worker\r\n */\r\n private _destroyWorker(worker: Worker): void {\r\n const aliveIndex: number = this._alive.indexOf(worker);\r\n if (aliveIndex >= 0) {\r\n this._alive.splice(aliveIndex, 1);\r\n }\r\n\r\n const freeIndex: number = this._idle.indexOf(worker);\r\n if (freeIndex >= 0) {\r\n this._idle.splice(freeIndex, 1);\r\n }\r\n\r\n worker.unref();\r\n\r\n if (this._onWorkerDestroyed) {\r\n this._onWorkerDestroyed();\r\n }\r\n\r\n if (!this._alive.length && !this._error) {\r\n for (const [resolve] of this._onComplete.splice(0)) {\r\n resolve();\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Notifies all pending callbacks that an error has occurred and switches this pool into error state.\r\n */\r\n private _onError(error: Error): void {\r\n this._error = error;\r\n\r\n for (const [, reject] of this._pending.splice(0)) {\r\n reject(this._error);\r\n }\r\n\r\n for (const [, reject] of this._onComplete.splice(0)) {\r\n reject(this._error);\r\n }\r\n }\r\n}\r\n"]} | ||
| {"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 { Worker } from '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/**\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\n public constructor(options: IWorkerPoolOptions) {\n const { id, maxWorkers, onWorkerDestroyed, prepareWorker, workerData, workerScriptPath } = 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 }\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 });\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.on('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"]} |
+0
-0
@@ -0,0 +0,0 @@ @rushstack/worker-pool |
+3
-3
| { | ||
| "name": "@rushstack/worker-pool", | ||
| "version": "0.4.10", | ||
| "version": "0.4.11", | ||
| "description": "Lightweight worker pool using NodeJS worker_threads", | ||
@@ -14,4 +14,4 @@ "main": "lib/index.js", | ||
| "devDependencies": { | ||
| "@rushstack/heft": "0.63.0", | ||
| "local-node-rig": "1.0.0" | ||
| "local-node-rig": "1.0.0", | ||
| "@rushstack/heft": "0.63.1" | ||
| }, | ||
@@ -18,0 +18,0 @@ "peerDependencies": { |
+0
-0
@@ -0,0 +0,0 @@ # @rushstack/worker-pool |
29043
-1.98%