Add eslint jsdoc plugin and refine a bit the existing comments.
[e-mobility-charging-stations-simulator.git] / src / worker / WorkerSet.ts
1 import { WorkerEvents, WorkerSetElement } from '../types/Worker';
2
3 import Constants from '../utils/Constants';
4 import Utils from '../utils/Utils';
5 import { Worker } from 'worker_threads';
6 import WorkerAbstract from './WorkerAbstract';
7
8 export default class WorkerSet<T> extends WorkerAbstract {
9 public maxElementsPerWorker: number;
10 private workerSet: Set<WorkerSetElement>;
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);
20 this.workerSet = new Set<WorkerSetElement>();
21 this.maxElementsPerWorker = maxElementsPerWorker;
22 }
23
24 get size(): number {
25 return this.workerSet.size;
26 }
27
28 /**
29 *
30 * @param elementData
31 * @returns {Promise<void>}
32 * @public
33 */
34 public async addElement(elementData: T): Promise<void> {
35 if (!this.workerSet) {
36 throw Error('Cannot add a WorkerSet element: workers\' set does not exist');
37 }
38 if (this.getLastWorkerSetElement().numberOfWorkerElements >= this.maxElementsPerWorker) {
39 this.startWorker();
40 // Start worker sequentially to optimize memory at startup
41 await Utils.sleep(Constants.START_WORKER_DELAY);
42 }
43 this.getLastWorker().postMessage({ id: WorkerEvents.START_WORKER_ELEMENT, workerData: elementData });
44 this.getLastWorkerSetElement().numberOfWorkerElements++;
45 }
46
47 /**
48 *
49 * @returns {Promise<void>}
50 * @public
51 */
52 public async start(): Promise<void> {
53 this.startWorker();
54 // Start worker sequentially to optimize memory at startup
55 await Utils.sleep(Constants.START_WORKER_DELAY);
56 }
57
58 /**
59 *
60 * @returns {Promise<void>}
61 * @public
62 */
63 public async stop(): Promise<void> {
64 for (const workerSetElement of this.workerSet) {
65 await workerSetElement.worker.terminate();
66 }
67 this.workerSet.clear();
68 }
69
70 /**
71 *
72 * @returns {Promise}
73 * @private
74 */
75 private startWorker(): void {
76 const worker = new Worker(this.workerScript);
77 worker.on('message', () => { });
78 worker.on('error', () => { });
79 worker.on('exit', (code) => {
80 if (code !== 0) {
81 console.error(`Worker stopped with exit code ${code}`);
82 }
83 this.workerSet.delete(this.getWorkerSetElementByWorker(worker));
84 });
85 this.workerSet.add({ worker, numberOfWorkerElements: 0 });
86 }
87
88 private getLastWorkerSetElement(): WorkerSetElement {
89 let workerSetElement: WorkerSetElement;
90 // eslint-disable-next-line no-empty
91 for (workerSetElement of this.workerSet) { }
92 return workerSetElement;
93 }
94
95 private getLastWorker(): Worker {
96 return this.getLastWorkerSetElement().worker;
97 }
98
99 private getWorkerSetElementByWorker(worker: Worker): WorkerSetElement {
100 let workerSetElt: WorkerSetElement;
101 this.workerSet.forEach((workerSetElement) => {
102 if (JSON.stringify(workerSetElement.worker) === JSON.stringify(worker)) {
103 workerSetElt = workerSetElement;
104 }
105 });
106 return workerSetElt;
107 }
108 }