+ private checkNumberOfWorkers (numberOfWorkers: number): void {
+ if (numberOfWorkers == null) {
+ throw new Error(
+ 'Cannot instantiate a pool without specifying the number of workers'
+ )
+ } else if (!Number.isSafeInteger(numberOfWorkers)) {
+ throw new TypeError(
+ 'Cannot instantiate a pool with a non safe integer number of workers'
+ )
+ } else if (numberOfWorkers < 0) {
+ throw new RangeError(
+ 'Cannot instantiate a pool with a negative number of workers'
+ )
+ } else if (this.type === PoolType.FIXED && numberOfWorkers === 0) {
+ throw new Error('Cannot instantiate a fixed pool with no worker')
+ }
+ }
+
+ private checkPoolOptions (opts: PoolOptions<Worker>): void {
+ if (isPlainObject(opts)) {
+ this.opts.workerChoiceStrategy =
+ opts.workerChoiceStrategy ?? WorkerChoiceStrategies.ROUND_ROBIN
+ this.checkValidWorkerChoiceStrategy(this.opts.workerChoiceStrategy)
+ this.opts.workerChoiceStrategyOptions =
+ opts.workerChoiceStrategyOptions ??
+ DEFAULT_WORKER_CHOICE_STRATEGY_OPTIONS
+ this.checkValidWorkerChoiceStrategyOptions(
+ this.opts.workerChoiceStrategyOptions
+ )
+ this.opts.enableEvents = opts.enableEvents ?? true
+ this.opts.enableTasksQueue = opts.enableTasksQueue ?? false
+ if (this.opts.enableTasksQueue) {
+ this.checkValidTasksQueueOptions(
+ opts.tasksQueueOptions as TasksQueueOptions
+ )
+ this.opts.tasksQueueOptions = this.buildTasksQueueOptions(
+ opts.tasksQueueOptions as TasksQueueOptions
+ )
+ }
+ } else {
+ throw new TypeError('Invalid pool options: must be a plain object')
+ }
+ }
+
+ private checkValidWorkerChoiceStrategy (
+ workerChoiceStrategy: WorkerChoiceStrategy
+ ): void {
+ if (!Object.values(WorkerChoiceStrategies).includes(workerChoiceStrategy)) {
+ throw new Error(
+ `Invalid worker choice strategy '${workerChoiceStrategy}'`
+ )
+ }
+ }
+
+ private checkValidWorkerChoiceStrategyOptions (
+ workerChoiceStrategyOptions: WorkerChoiceStrategyOptions
+ ): void {
+ if (!isPlainObject(workerChoiceStrategyOptions)) {
+ throw new TypeError(
+ 'Invalid worker choice strategy options: must be a plain object'
+ )
+ }
+ if (
+ workerChoiceStrategyOptions.weights != null &&
+ Object.keys(workerChoiceStrategyOptions.weights).length !== this.size
+ ) {
+ throw new Error(
+ 'Invalid worker choice strategy options: must have a weight for each worker node'
+ )
+ }
+ }
+
+ private checkValidTasksQueueOptions (
+ tasksQueueOptions: TasksQueueOptions
+ ): void {
+ if (tasksQueueOptions != null && !isPlainObject(tasksQueueOptions)) {
+ throw new TypeError('Invalid tasks queue options: must be a plain object')
+ }
+ if ((tasksQueueOptions?.concurrency as number) <= 0) {
+ throw new Error(
+ `Invalid worker tasks concurrency '${
+ tasksQueueOptions.concurrency as number
+ }'`
+ )
+ }
+ }
+
+ /** @inheritDoc */
+ public abstract get type (): PoolType
+
+ /** @inheritDoc */
+ public abstract get size (): number
+
+ /**
+ * Number of tasks running in the pool.
+ */
+ private get numberOfRunningTasks (): number {
+ return this.workerNodes.reduce(
+ (accumulator, workerNode) => accumulator + workerNode.tasksUsage.running,
+ 0
+ )
+ }
+
+ /**
+ * Number of tasks queued in the pool.
+ */
+ private get numberOfQueuedTasks (): number {
+ if (this.opts.enableTasksQueue === false) {
+ return 0
+ }
+ return this.workerNodes.reduce(
+ (accumulator, workerNode) => accumulator + workerNode.tasksQueue.size,
+ 0
+ )
+ }
+