Merge branch 'master' of github.com:LucasBrazi06/ev-simulator into master-enterprise
[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 Wrk from './Wrk';
7
8 export default class WorkerSet<T> extends Wrk {
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 * @return {Promise<void>}
31 * @public
32 */
33 public async addElement(elementData: T): Promise<void> {
34 if (!this.workerSet) {
35 throw Error('Cannot add a WorkerSet element: workers\' set does not exist');
36 }
37 if (this.getLastWorkerSetElement().numberOfWorkerElements >= this.maxElementsPerWorker) {
38 this.startWorker();
39 // Start worker sequentially to optimize memory at startup
40 await Utils.sleep(Constants.START_WORKER_DELAY);
41 }
42 this.getLastWorker().postMessage({ id: WorkerEvents.START_WORKER_ELEMENT, workerData: elementData });
43 this.getLastWorkerSetElement().numberOfWorkerElements++;
44 }
45
46 /**
47 *
48 * @return {Promise<void>}
49 * @public
50 */
51 public async start(): Promise<void> {
52 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<void>}
60 * @public
61 */
62 public async stop(): Promise<void> {
63 for (const workerSetElement of this.workerSet) {
64 await workerSetElement.worker.terminate();
65 }
66 this.workerSet.clear();
67 }
68
69 /**
70 *
71 * @return {Promise}
72 * @private
73 */
74 private startWorker(): void {
75 const worker = new Worker(this.workerScript);
76 worker.on('message', () => { });
77 worker.on('error', () => { });
78 worker.on('exit', (code) => {
79 if (code !== 0) {
80 console.error(`Worker stopped with exit code ${code}`);
81 }
82 // FIXME: remove matching worker set element
83 });
84 this.workerSet.add({ worker, numberOfWorkerElements: 0 });
85 }
86
87 private getLastWorkerSetElement(): WorkerSetElement {
88 let workerSetElement: WorkerSetElement;
89 // eslint-disable-next-line no-empty
90 for (workerSetElement of this.workerSet) { }
91 return workerSetElement;
92 }
93
94 private getLastWorker(): Worker {
95 return this.getLastWorkerSetElement().worker;
96 }
97
98 private getWorkerSetElementByWorker(worker: Worker): WorkerSetElement {
99 let workerSetElt: WorkerSetElement;
100 this.workerSet.forEach((workerSetElement) => {
101 if (JSON.stringify(workerSetElement.worker) === JSON.stringify(worker)) {
102 workerSetElt = workerSetElement;
103 }
104 });
105 return workerSetElt;
106 }
107 }