Don't access singleton instance attribute directly
[e-mobility-charging-stations-simulator.git] / src / charging-station / Worker.ts
CommitLineData
f98fbdb9
JB
1import { Worker, WorkerOptions } from 'worker_threads';
2
6af9012e 3import Configuration from '../utils/Configuration';
5fdab605 4import Constants from '../utils/Constants';
3f40bc9c 5import Pool from 'worker-threads-pool';
ad3de6c4 6import WorkerData from '../types/WorkerData';
7dde0b73 7
3f40bc9c 8export default class Wrk {
ad3de6c4
JB
9 private _workerScript: string;
10 private _workerData: WorkerData;
3d2ff9e4 11 private _worker: Worker;
6af9012e 12
7dde0b73
JB
13 /**
14 * Create a new `Wrk`.
15 *
ad3de6c4
JB
16 * @param {string} workerScript
17 * @param {WorkerData} workerData
7dde0b73 18 */
4faad557 19 constructor(workerScript: string, workerData: WorkerData) {
6798437b
JB
20 this._workerData = workerData;
21 this._workerScript = workerScript;
7dde0b73 22 if (Configuration.useWorkerPool()) {
4fa59b8a 23 WorkerPool.maxConcurrentWorkers = Configuration.getWorkerPoolMaxSize();
7dde0b73 24 }
7dde0b73
JB
25 }
26
6af9012e
JB
27 /**
28 *
29 * @return {Promise}
30 * @public
31 */
3d2ff9e4 32 async start(): Promise<Worker> {
6af9012e 33 if (Configuration.useWorkerPool()) {
5fdab605 34 await this._startWorkerWithPool();
3d2ff9e4 35 } else {
5fdab605 36 await this._startWorker();
6af9012e 37 }
3d2ff9e4
J
38 return this._worker;
39 }
40
5fdab605 41 /**
3d2ff9e4 42 *
5fdab605 43 * @return {void}
3d2ff9e4
J
44 * @public
45 */
97ed5cec
JB
46 addWorkerElement(workerData: WorkerData): void {
47 // FIXME: also forbid to add an element if the current number of elements > max number of elements
48 if (Configuration.useWorkerPool()) {
49 return;
50 }
3d2ff9e4 51 this._workerData = workerData;
4fa59b8a
JB
52 this._worker.postMessage({ id: Constants.START_WORKER_ELEMENT, workerData: workerData });
53 }
54
55 /**
56 *
57 * @return {number}
58 * @public
59 */
60 public getWorkerPoolSize(): number {
61 if (Configuration.useWorkerPool()) {
62 return WorkerPool.getPoolSize();
63 }
6af9012e
JB
64 }
65
7dde0b73
JB
66 /**
67 *
68 * @return {Promise}
69 * @private
70 */
6af9012e 71 private async _startWorkerWithPool() {
7dde0b73 72 return new Promise((resolve, reject) => {
f98fbdb9 73 WorkerPool.acquire(this._workerScript, { workerData: this._workerData }, (err, worker) => {
7dde0b73
JB
74 if (err) {
75 return reject(err);
76 }
77 worker.once('message', resolve);
78 worker.once('error', reject);
3d2ff9e4 79 this._worker = worker;
7dde0b73
JB
80 });
81 });
82 }
83
84 /**
85 *
86 * @return {Promise}
87 * @private
88 */
6af9012e 89 private async _startWorker() {
7dde0b73 90 return new Promise((resolve, reject) => {
6af9012e 91 const worker = new Worker(this._workerScript, { workerData: this._workerData });
7dde0b73
JB
92 worker.on('message', resolve);
93 worker.on('error', reject);
94 worker.on('exit', (code) => {
95 if (code !== 0) {
4faad557 96 reject(new Error(`Worker stopped with exit code ${code}`));
7dde0b73
JB
97 }
98 });
3d2ff9e4 99 this._worker = worker;
7dde0b73
JB
100 });
101 }
7dde0b73 102}
f98fbdb9 103
72a965c4 104
f98fbdb9 105class WorkerPool {
97ed5cec 106 public static maxConcurrentWorkers: number;
f98fbdb9
JB
107 private static _instance: Pool;
108
109 private constructor() { }
110
111 public static getInstance(): Pool {
97ed5cec
JB
112 if (!WorkerPool._instance) {
113 WorkerPool._instance = new Pool({ max: WorkerPool.maxConcurrentWorkers });
f98fbdb9
JB
114 }
115 return WorkerPool._instance;
116 }
117
118 public static acquire(filename: string, options: WorkerOptions, callback: (error: Error | null, worker: Worker) => void): void {
119 WorkerPool.getInstance().acquire(filename, options, callback);
120 }
72a965c4
J
121
122 public static getPoolSize(): number {
4fa59b8a 123 return WorkerPool.getInstance().size;
72a965c4 124 }
f98fbdb9 125}