X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=src%2Fcharging-station%2FBootstrap.ts;h=5356a15569fbce4db81a738dc7e24274d93f2118;hb=c2be11fddae3fd9c84ab92719e3d479301eb0257;hp=de4389780d2aec671f2f3293ea0dc3a5beb670ba;hpb=c5ecc04daa3a6102cd586af446547dee585d506b;p=e-mobility-charging-stations-simulator.git diff --git a/src/charging-station/Bootstrap.ts b/src/charging-station/Bootstrap.ts index de438978..5356a155 100644 --- a/src/charging-station/Bootstrap.ts +++ b/src/charging-station/Bootstrap.ts @@ -18,7 +18,9 @@ import { BaseError } from '../exception/index.js' import { type Storage, StorageFactory } from '../performance/index.js' import { type ChargingStationData, + type ChargingStationOptions, type ChargingStationWorkerData, + type ChargingStationWorkerEventError, type ChargingStationWorkerMessage, type ChargingStationWorkerMessageData, ChargingStationWorkerMessageEvents, @@ -54,16 +56,19 @@ enum exitCodes { gracefulShutdownError = 4 } +interface TemplateChargingStations { + configured: number + added: number + started: number + lastIndex: number +} + export class Bootstrap extends EventEmitter { private static instance: Bootstrap | null = null private workerImplementation?: WorkerAbstract private readonly uiServer?: AbstractUIServer private storage?: Storage - private readonly chargingStationsByTemplate: Map< - string, - { configured: number, started: number, lastIndex: number } - > - + private readonly chargingStationsByTemplate: Map private readonly version: string = version private initializedCounters: boolean private started: boolean @@ -81,10 +86,7 @@ export class Bootstrap extends EventEmitter { this.started = false this.starting = false this.stopping = false - this.chargingStationsByTemplate = new Map< - string, - { configured: number, started: number, lastIndex: number } - >() + this.chargingStationsByTemplate = new Map() this.uiServer = UIServerFactory.getUIServerImplementation( Configuration.getConfigurationSection(ConfigurationSection.uiServer) ) @@ -119,6 +121,17 @@ export class Bootstrap extends EventEmitter { return this.chargingStationsByTemplate.get(templateName)?.lastIndex ?? 0 } + public getPerformanceStatistics (): IterableIterator | undefined { + return this.storage?.getPerformanceStatistics() + } + + private get numberOfAddedChargingStations (): number { + return [...this.chargingStationsByTemplate.values()].reduce( + (accumulator, value) => accumulator + value.added, + 0 + ) + } + private get numberOfStartedChargingStations (): number { return [...this.chargingStationsByTemplate.values()].reduce( (accumulator, value) => accumulator + value.started, @@ -130,6 +143,8 @@ export class Bootstrap extends EventEmitter { if (!this.started) { if (!this.starting) { this.starting = true + this.on(ChargingStationWorkerMessageEvents.added, this.workerEventAdded) + this.on(ChargingStationWorkerMessageEvents.deleted, this.workerEventDeleted) this.on(ChargingStationWorkerMessageEvents.started, this.workerEventStarted) this.on(ChargingStationWorkerMessageEvents.stopped, this.workerEventStopped) this.on(ChargingStationWorkerMessageEvents.updated, this.workerEventUpdated) @@ -137,6 +152,15 @@ export class Bootstrap extends EventEmitter { ChargingStationWorkerMessageEvents.performanceStatistics, this.workerEventPerformanceStatistics ) + this.on( + ChargingStationWorkerMessageEvents.workerElementError, + (eventError: ChargingStationWorkerEventError) => { + logger.error( + `${this.logPrefix()} ${moduleName}.start: Error occurred while handling '${eventError.event}' event on worker:`, + eventError + ) + } + ) this.initializeCounters() const workerConfiguration = Configuration.getConfigurationSection( ConfigurationSection.worker @@ -244,7 +268,7 @@ export class Bootstrap extends EventEmitter { private async restart (): Promise { await this.stop() Configuration.getConfigurationSection(ConfigurationSection.uiServer) - .enabled === false && this.uiServer?.stop() + .enabled !== true && this.uiServer?.stop() this.initializedCounters = false await this.start() } @@ -277,17 +301,18 @@ export class Bootstrap extends EventEmitter { if (!isMainThread) { return } - let elementsPerWorker: number | undefined + let elementsPerWorker: number switch (workerConfiguration.elementsPerWorker) { + case 'all': + elementsPerWorker = this.numberOfConfiguredChargingStations + break case 'auto': + default: elementsPerWorker = this.numberOfConfiguredChargingStations > availableParallelism() ? Math.round(this.numberOfConfiguredChargingStations / (availableParallelism() * 1.5)) : 1 break - case 'all': - elementsPerWorker = this.numberOfConfiguredChargingStations - break } this.workerImplementation = WorkerFactory.getWorkerImplementation( join( @@ -303,7 +328,7 @@ export class Bootstrap extends EventEmitter { poolMaxSize: workerConfiguration.poolMaxSize!, // eslint-disable-next-line @typescript-eslint/no-non-null-assertion poolMinSize: workerConfiguration.poolMinSize!, - elementsPerWorker: elementsPerWorker ?? (workerConfiguration.elementsPerWorker as number), + elementsPerWorker, poolOptions: { messageHandler: this.messageHandler.bind(this) as MessageHandler, workerOptions: { resourceLimits: workerConfiguration.resourceLimits } @@ -324,29 +349,29 @@ export class Bootstrap extends EventEmitter { // ) try { switch (msg.event) { + case ChargingStationWorkerMessageEvents.added: + this.emit(ChargingStationWorkerMessageEvents.added, msg.data) + break + case ChargingStationWorkerMessageEvents.deleted: + this.emit(ChargingStationWorkerMessageEvents.deleted, msg.data) + break case ChargingStationWorkerMessageEvents.started: - this.emit(ChargingStationWorkerMessageEvents.started, msg.data as ChargingStationData) + this.emit(ChargingStationWorkerMessageEvents.started, msg.data) break case ChargingStationWorkerMessageEvents.stopped: - this.emit(ChargingStationWorkerMessageEvents.stopped, msg.data as ChargingStationData) + this.emit(ChargingStationWorkerMessageEvents.stopped, msg.data) break case ChargingStationWorkerMessageEvents.updated: - this.emit(ChargingStationWorkerMessageEvents.updated, msg.data as ChargingStationData) + this.emit(ChargingStationWorkerMessageEvents.updated, msg.data) break case ChargingStationWorkerMessageEvents.performanceStatistics: - this.emit( - ChargingStationWorkerMessageEvents.performanceStatistics, - msg.data as Statistics - ) + this.emit(ChargingStationWorkerMessageEvents.performanceStatistics, msg.data) break - case ChargingStationWorkerMessageEvents.startWorkerElementError: - logger.error( - `${this.logPrefix()} ${moduleName}.messageHandler: Error occurred while starting worker element:`, - msg.data - ) - this.emit(ChargingStationWorkerMessageEvents.startWorkerElementError, msg.data) + case ChargingStationWorkerMessageEvents.addedWorkerElement: + this.emit(ChargingStationWorkerMessageEvents.addWorkerElement, msg.data) break - case ChargingStationWorkerMessageEvents.startedWorkerElement: + case ChargingStationWorkerMessageEvents.workerElementError: + this.emit(ChargingStationWorkerMessageEvents.workerElementError, msg.data) break default: throw new BaseError( @@ -365,6 +390,32 @@ export class Bootstrap extends EventEmitter { } } + private readonly workerEventAdded = (data: ChargingStationData): void => { + this.uiServer?.chargingStations.set(data.stationInfo.hashId, data) + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + ++this.chargingStationsByTemplate.get(data.stationInfo.templateName)!.added + logger.info( + `${this.logPrefix()} ${moduleName}.workerEventAdded: Charging station ${ + data.stationInfo.chargingStationId + } (hashId: ${data.stationInfo.hashId}) added (${ + this.numberOfAddedChargingStations + } added from ${this.numberOfConfiguredChargingStations} configured charging station(s))` + ) + } + + private readonly workerEventDeleted = (data: ChargingStationData): void => { + this.uiServer?.chargingStations.delete(data.stationInfo.hashId) + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + --this.chargingStationsByTemplate.get(data.stationInfo.templateName)!.added + logger.info( + `${this.logPrefix()} ${moduleName}.workerEventDeleted: Charging station ${ + data.stationInfo.chargingStationId + } (hashId: ${data.stationInfo.hashId}) deleted (${ + this.numberOfAddedChargingStations + } added from ${this.numberOfConfiguredChargingStations} configured charging station(s))` + ) + } + private readonly workerEventStarted = (data: ChargingStationData): void => { this.uiServer?.chargingStations.set(data.stationInfo.hashId, data) // eslint-disable-next-line @typescript-eslint/no-non-null-assertion @@ -374,7 +425,7 @@ export class Bootstrap extends EventEmitter { data.stationInfo.chargingStationId } (hashId: ${data.stationInfo.hashId}) started (${ this.numberOfStartedChargingStations - } started from ${this.numberOfConfiguredChargingStations} configured charging station(s))` + } started from ${this.numberOfAddedChargingStations} added charging station(s))` ) } @@ -387,7 +438,7 @@ export class Bootstrap extends EventEmitter { data.stationInfo.chargingStationId } (hashId: ${data.stationInfo.hashId}) stopped (${ this.numberOfStartedChargingStations - } started from ${this.numberOfConfiguredChargingStations} configured charging station(s))` + } started from ${this.numberOfAddedChargingStations} added charging station(s))` ) } @@ -419,6 +470,7 @@ export class Bootstrap extends EventEmitter { const templateName = parse(stationTemplateUrl.file).name this.chargingStationsByTemplate.set(templateName, { configured: stationTemplateUrl.numberOfStations, + added: 0, started: 0, lastIndex: 0 }) @@ -441,7 +493,7 @@ export class Bootstrap extends EventEmitter { if ( this.numberOfConfiguredChargingStations === 0 && Configuration.getConfigurationSection(ConfigurationSection.uiServer) - .enabled === true + .enabled !== true ) { console.error( chalk.red( @@ -454,7 +506,11 @@ export class Bootstrap extends EventEmitter { } } - public async addChargingStation (index: number, stationTemplateFile: string): Promise { + public async addChargingStation ( + index: number, + stationTemplateFile: string, + options?: ChargingStationOptions + ): Promise { await this.workerImplementation?.addElement({ index, templateFile: join( @@ -462,7 +518,8 @@ export class Bootstrap extends EventEmitter { 'assets', 'station-templates', stationTemplateFile - ) + ), + options }) // eslint-disable-next-line @typescript-eslint/no-non-null-assertion this.chargingStationsByTemplate.get(parse(stationTemplateFile).name)!.lastIndex = max( @@ -476,7 +533,6 @@ export class Bootstrap extends EventEmitter { .then(() => { console.info(chalk.green('Graceful shutdown')) this.uiServer?.stop() - // stop() asks for charging stations to stop by default this.waitChargingStationsStopped() .then(() => { exit(exitCodes.succeeded)