fix: ensure remote start transaction triggers a delayed start transaction
[e-mobility-charging-stations-simulator.git] / src / charging-station / Bootstrap.ts
index 5b23676f24e39049cedf24f7581132f5b265a925..f09864d4ed66d935960084061359fe6ca7af3799 100644 (file)
@@ -1,12 +1,13 @@
-// Partial Copyright Jerome Benoit. 2021-2023. All Rights Reserved.
+// Partial Copyright Jerome Benoit. 2021-2024. All Rights Reserved.
 
 import { EventEmitter } from 'node:events'
 import { dirname, extname, join } from 'node:path'
 import process, { exit } from 'node:process'
 import { fileURLToPath } from 'node:url'
+import type { Worker } from 'worker_threads'
 
 import chalk from 'chalk'
-import { availableParallelism } from 'poolifier'
+import { type MessageHandler, availableParallelism } from 'poolifier'
 
 import { waitChargingStationEvents } from './Helpers.js'
 import type { AbstractUIServer } from './ui-server/AbstractUIServer.js'
@@ -35,6 +36,7 @@ import {
   generateUUID,
   handleUncaughtException,
   handleUnhandledRejection,
+  isAsyncFunction,
   isNotEmptyArray,
   logPrefix,
   logger
@@ -47,7 +49,7 @@ enum exitCodes {
   succeeded = 0,
   missingChargingStationsConfiguration = 1,
   noChargingStationTemplates = 2,
-  gracefulShutdownError = 3,
+  gracefulShutdownError = 3
 }
 
 export class Bootstrap extends EventEmitter {
@@ -129,7 +131,7 @@ export class Bootstrap extends EventEmitter {
         // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
         for (const stationTemplateUrl of Configuration.getStationTemplateUrls()!) {
           try {
-            const nbStations = stationTemplateUrl.numberOfStations ?? 0
+            const nbStations = stationTemplateUrl.numberOfStations
             for (let index = 1; index <= nbStations; index++) {
               await this.startChargingStation(index, stationTemplateUrl)
             }
@@ -156,7 +158,7 @@ export class Bootstrap extends EventEmitter {
                 : ''
             } worker(s) concurrently running in '${workerConfiguration.processType}' mode${
               this.workerImplementation?.maxElementsPerWorker != null
-                ? ` (${this.workerImplementation?.maxElementsPerWorker} charging station(s) per worker)`
+                ? ` (${this.workerImplementation.maxElementsPerWorker} charging station(s) per worker)`
                 : ''
             }`
           )
@@ -223,16 +225,16 @@ export class Bootstrap extends EventEmitter {
   private async waitChargingStationsStopped (): Promise<string> {
     return await new Promise<string>((resolve, reject) => {
       const waitTimeout = setTimeout(() => {
-        const message = `Timeout ${formatDurationMilliSeconds(
+        const timeoutMessage = `Timeout ${formatDurationMilliSeconds(
           Constants.STOP_CHARGING_STATIONS_TIMEOUT
         )} reached at stopping charging stations`
-        console.warn(chalk.yellow(message))
-        reject(new Error(message))
+        console.warn(chalk.yellow(timeoutMessage))
+        reject(new Error(timeoutMessage))
       }, Constants.STOP_CHARGING_STATIONS_TIMEOUT)
       waitChargingStationEvents(
         this,
         ChargingStationWorkerMessageEvents.stopped,
-        this.numberOfChargingStations
+        this.numberOfStartedChargingStations
       )
         .then(() => {
           resolve('Charging stations stopped')
@@ -246,7 +248,7 @@ export class Bootstrap extends EventEmitter {
 
   private initializeWorkerImplementation (workerConfiguration: WorkerConfiguration): void {
     let elementsPerWorker: number | undefined
-    switch (workerConfiguration?.elementsPerWorker) {
+    switch (workerConfiguration.elementsPerWorker) {
       case 'auto':
         elementsPerWorker =
           this.numberOfChargingStations > availableParallelism()
@@ -273,7 +275,7 @@ export class Bootstrap extends EventEmitter {
         poolMinSize: workerConfiguration.poolMinSize!,
         elementsPerWorker: elementsPerWorker ?? (workerConfiguration.elementsPerWorker as number),
         poolOptions: {
-          messageHandler: this.messageHandler.bind(this) as (message: unknown) => void,
+          messageHandler: this.messageHandler.bind(this) as MessageHandler<Worker>,
           workerOptions: { resourceLimits: workerConfiguration.resourceLimits }
         }
       }
@@ -362,7 +364,18 @@ export class Bootstrap extends EventEmitter {
   }
 
   private readonly workerEventPerformanceStatistics = (data: Statistics): void => {
-    this.storage?.storePerformanceStatistics(data) as undefined
+    // eslint-disable-next-line @typescript-eslint/unbound-method
+    if (isAsyncFunction(this.storage?.storePerformanceStatistics)) {
+      (
+        this.storage.storePerformanceStatistics as (
+          performanceStatistics: Statistics
+        ) => Promise<void>
+      )(data).catch(Constants.EMPTY_FUNCTION)
+    } else {
+      (this.storage?.storePerformanceStatistics as (performanceStatistics: Statistics) => void)(
+        data
+      )
+    }
   }
 
   private initializeCounters (): void {
@@ -373,7 +386,7 @@ export class Bootstrap extends EventEmitter {
       if (isNotEmptyArray(stationTemplateUrls)) {
         this.numberOfChargingStationTemplates = stationTemplateUrls.length
         for (const stationTemplateUrl of stationTemplateUrls) {
-          this.numberOfChargingStations += stationTemplateUrl.numberOfStations ?? 0
+          this.numberOfChargingStations += stationTemplateUrl.numberOfStations
         }
       } else {
         console.warn(
@@ -413,7 +426,7 @@ export class Bootstrap extends EventEmitter {
   private gracefulShutdown (): void {
     this.stop()
       .then(() => {
-        console.info(`${chalk.green('Graceful shutdown')}`)
+        console.info(chalk.green('Graceful shutdown'))
         this.uiServer?.stop()
         // stop() asks for charging stations to stop by default
         this.waitChargingStationsStopped()
@@ -424,7 +437,7 @@ export class Bootstrap extends EventEmitter {
             exit(exitCodes.gracefulShutdownError)
           })
       })
-      .catch((error) => {
+      .catch(error => {
         console.error(chalk.red('Error while shutdowning charging stations simulator: '), error)
         exit(exitCodes.gracefulShutdownError)
       })