Merge dependabot/npm_and_yarn/typescript-eslint/parser-6.7.5 into combined-prs-branch
[e-mobility-charging-stations-simulator.git] / src / worker / WorkerSet.ts
index 7ddc96c73c27febb8a179a9faa4da6ee01c0615a..c5df860ced4fc85b16e7067c805605b05db75e04 100644 (file)
@@ -1,6 +1,6 @@
 // Partial Copyright Jerome Benoit. 2021-2023. All Rights Reserved.
 
-import { EventEmitter } from 'node:events';
+import { EventEmitterAsyncResource } from 'node:events';
 import { SHARE_ENV, Worker } from 'node:worker_threads';
 
 import { WorkerAbstract } from './WorkerAbstract';
@@ -14,10 +14,10 @@ import {
   type WorkerSetElement,
   WorkerSetEvents,
 } from './WorkerTypes';
-import { sleep } from './WorkerUtils';
+import { randomizeDelay, sleep } from './WorkerUtils';
 
 export class WorkerSet extends WorkerAbstract<WorkerData> {
-  public readonly emitter!: EventEmitter;
+  public readonly emitter: EventEmitterAsyncResource | undefined;
   private readonly workerSet: Set<WorkerSetElement>;
   private started: boolean;
   private workerStartup: boolean;
@@ -44,7 +44,7 @@ export class WorkerSet extends WorkerAbstract<WorkerData> {
     }
     this.workerSet = new Set<WorkerSetElement>();
     if (this.workerOptions.poolOptions?.enableEvents) {
-      this.emitter = new EventEmitter();
+      this.emitter = new EventEmitterAsyncResource({ name: 'workerset' });
     }
     this.started = false;
     this.workerStartup = false;
@@ -76,7 +76,9 @@ export class WorkerSet extends WorkerAbstract<WorkerData> {
   public async start(): Promise<void> {
     this.addWorkerSetElement();
     // Add worker set element sequentially to optimize memory at startup
-    this.workerOptions.workerStartDelay! > 0 && (await sleep(this.workerOptions.workerStartDelay!));
+    this.workerOptions.workerStartDelay! > 0 &&
+      (await sleep(randomizeDelay(this.workerOptions.workerStartDelay!)));
+    this.emitter?.emit(WorkerSetEvents.started, this.info);
     this.started = true;
   }
 
@@ -85,12 +87,14 @@ export class WorkerSet extends WorkerAbstract<WorkerData> {
     for (const workerSetElement of this.workerSet) {
       const worker = workerSetElement.worker;
       const waitWorkerExit = new Promise<void>((resolve) => {
-        worker.on('exit', () => {
+        worker.once('exit', () => {
           resolve();
         });
       });
       await worker.terminate();
       await waitWorkerExit;
+      this.emitter?.emit(WorkerSetEvents.stopped, this.info);
+      this.emitter?.emitDestroy();
       this.started = false;
     }
   }
@@ -111,7 +115,7 @@ export class WorkerSet extends WorkerAbstract<WorkerData> {
     ++workerSetElement.numberOfWorkerElements;
     // Add element sequentially to optimize memory at startup
     if (this.workerOptions.elementStartDelay! > 0) {
-      await sleep(this.workerOptions.elementStartDelay!);
+      await sleep(randomizeDelay(this.workerOptions.elementStartDelay!));
     }
   }
 
@@ -170,7 +174,7 @@ export class WorkerSet extends WorkerAbstract<WorkerData> {
       chosenWorkerSetElement = this.addWorkerSetElement();
       // Add worker set element sequentially to optimize memory at startup
       this.workerOptions.workerStartDelay! > 0 &&
-        (await sleep(this.workerOptions.workerStartDelay!));
+        (await sleep(randomizeDelay(this.workerOptions.workerStartDelay!)));
     }
     return chosenWorkerSetElement;
   }