Use object factory design pattern for code handling workers.
[e-mobility-charging-stations-simulator.git] / src / worker / WorkerSet.ts
CommitLineData
6013bc53
JB
1import Constants from '../utils/Constants';
2import Utils from '../utils/Utils';
3import { Worker } from 'worker_threads';
4import WorkerData from '../types/WorkerData';
5import Wrk from './Worker';
6
7export default class WorkerSet extends Wrk {
8 public maxElementsPerWorker: number;
9 private workers: Set<Worker>;
10 private lastWorkerNumberOfElements: number;
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.workers = new Set<Worker>();
21 this.maxElementsPerWorker = maxElementsPerWorker;
22 this.lastWorkerNumberOfElements = 0;
23 }
24
25 get size(): number {
26 return this.workers.size;
27 }
28
29 /**
30 *
31 * @return {Promise<void>}
32 * @public
33 */
34 public async addElement(elementData: WorkerData): Promise<void> {
35 if (!this.workers) {
36 throw Error('Cannot add a WorkerSet element: workers set does not exist');
37 }
38 if (this.lastWorkerNumberOfElements >= this.maxElementsPerWorker) {
39 void this.startWorker();
40 this.lastWorkerNumberOfElements = 0;
41 // Start worker sequentially to optimize memory at startup
42 void Utils.sleep(Constants.START_WORKER_DELAY);
43 }
44 this.getLastWorker().postMessage({ id: Constants.START_WORKER_ELEMENT, workerData: elementData });
45 this.lastWorkerNumberOfElements++;
46 }
47
48 /**
49 *
50 * @return {Promise<void>}
51 * @public
52 */
53 public async start(): Promise<void> {
54 await this.startWorker();
55 // Start worker sequentially to optimize memory at startup
56 await Utils.sleep(Constants.START_WORKER_DELAY);
57 }
58
59 /**
60 *
61 * @return {Promise}
62 * @private
63 */
64 private async startWorker() {
65 return new Promise((resolve, reject) => {
66 const worker = new Worker(this.workerScript);
67 worker.on('message', resolve);
68 worker.on('error', reject);
69 worker.on('exit', (code) => {
70 if (code !== 0) {
71 reject(new Error(`Worker stopped with exit code ${code}`));
72 }
73 });
74 this.workers.add(worker);
75 });
76 }
77
78 private getLastWorker(): Worker {
79 let worker: Worker;
80 // eslint-disable-next-line no-empty
81 for (worker of this.workers) { }
82 return worker;
83 }
84}