Commit | Line | Data |
---|---|---|
c045d9a9 JB |
1 | import { WorkerData, WorkerEvents, WorkerSetElement } from '../types/Worker'; |
2 | ||
6013bc53 JB |
3 | import Constants from '../utils/Constants'; |
4 | import Utils from '../utils/Utils'; | |
5 | import { Worker } from 'worker_threads'; | |
144cabe0 | 6 | import Wrk from './Wrk'; |
6013bc53 JB |
7 | |
8 | export default class WorkerSet extends Wrk { | |
9 | public maxElementsPerWorker: number; | |
c045d9a9 | 10 | private workers: Set<WorkerSetElement>; |
6013bc53 JB |
11 | |
12 | /** | |
13 | * Create a new `WorkerSet`. | |
14 | * | |
15 | * @param {string} workerScript | |
16 | * @param {number} maxElementsPerWorker | |
17 | */ | |
18 | constructor(workerScript: string, maxElementsPerWorker = 1) { | |
19 | super(workerScript); | |
c045d9a9 | 20 | this.workers = new Set<WorkerSetElement>(); |
6013bc53 | 21 | this.maxElementsPerWorker = maxElementsPerWorker; |
6013bc53 JB |
22 | } |
23 | ||
24 | get size(): number { | |
25 | return this.workers.size; | |
26 | } | |
27 | ||
28 | /** | |
29 | * | |
30 | * @return {Promise<void>} | |
31 | * @public | |
32 | */ | |
33 | public async addElement(elementData: WorkerData): Promise<void> { | |
34 | if (!this.workers) { | |
35 | throw Error('Cannot add a WorkerSet element: workers set does not exist'); | |
36 | } | |
c045d9a9 | 37 | if (this.getLastWorkerSetElement().numberOfWorkerElements >= this.maxElementsPerWorker) { |
6013bc53 | 38 | void this.startWorker(); |
6013bc53 JB |
39 | // Start worker sequentially to optimize memory at startup |
40 | void Utils.sleep(Constants.START_WORKER_DELAY); | |
41 | } | |
3e1416d8 | 42 | this.getLastWorker().postMessage({ id: WorkerEvents.START_WORKER_ELEMENT, workerData: elementData }); |
c045d9a9 | 43 | this.getLastWorkerSetElement().numberOfWorkerElements++; |
6013bc53 JB |
44 | } |
45 | ||
46 | /** | |
47 | * | |
48 | * @return {Promise<void>} | |
49 | * @public | |
50 | */ | |
51 | public async start(): Promise<void> { | |
52 | await this.startWorker(); | |
53 | // Start worker sequentially to optimize memory at startup | |
54 | await Utils.sleep(Constants.START_WORKER_DELAY); | |
55 | } | |
56 | ||
57 | /** | |
58 | * | |
59 | * @return {Promise} | |
60 | * @private | |
61 | */ | |
62 | private async startWorker() { | |
63 | return new Promise((resolve, reject) => { | |
64 | const worker = new Worker(this.workerScript); | |
65 | worker.on('message', resolve); | |
66 | worker.on('error', reject); | |
67 | worker.on('exit', (code) => { | |
68 | if (code !== 0) { | |
69 | reject(new Error(`Worker stopped with exit code ${code}`)); | |
70 | } | |
71 | }); | |
c045d9a9 | 72 | this.workers.add({ worker, numberOfWorkerElements: 0 }); |
6013bc53 JB |
73 | }); |
74 | } | |
75 | ||
c045d9a9 JB |
76 | private getLastWorkerSetElement(): WorkerSetElement { |
77 | let workerSetElement: WorkerSetElement; | |
6013bc53 | 78 | // eslint-disable-next-line no-empty |
c045d9a9 JB |
79 | for (workerSetElement of this.workers) { } |
80 | return workerSetElement; | |
81 | } | |
82 | ||
83 | private getLastWorker(): Worker { | |
84 | return this.getLastWorkerSetElement().worker; | |
6013bc53 JB |
85 | } |
86 | } |