X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=src%2Fcharging-station%2FBootstrap.ts;h=3993ae1f2a34a23ea3113b04b447512deb6474b9;hb=afbb820255fb5afe908c743ae53ae5a5f990c700;hp=07d411b59aaf763028e3a5d5ceb579e88de44177;hpb=887a125e6db5e0457e653b3c6848d18214558813;p=e-mobility-charging-stations-simulator.git diff --git a/src/charging-station/Bootstrap.ts b/src/charging-station/Bootstrap.ts index 07d411b5..3993ae1f 100644 --- a/src/charging-station/Bootstrap.ts +++ b/src/charging-station/Bootstrap.ts @@ -18,6 +18,7 @@ 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, @@ -40,8 +41,7 @@ import { isAsyncFunction, isNotEmptyArray, logPrefix, - logger, - max + logger } from '../utils/index.js' import { type WorkerAbstract, WorkerFactory } from '../worker/index.js' @@ -59,7 +59,7 @@ interface TemplateChargingStations { configured: number added: number started: number - lastIndex: number + indexes: Set } export class Bootstrap extends EventEmitter { @@ -67,7 +67,7 @@ export class Bootstrap extends EventEmitter { private workerImplementation?: WorkerAbstract private readonly uiServer?: AbstractUIServer private storage?: Storage - private readonly chargingStationsByTemplate: Map + private readonly templatesChargingStations: Map private readonly version: string = version private initializedCounters: boolean private started: boolean @@ -85,7 +85,7 @@ export class Bootstrap extends EventEmitter { this.started = false this.starting = false this.stopping = false - this.chargingStationsByTemplate = new Map() + this.templatesChargingStations = new Map() this.uiServer = UIServerFactory.getUIServerImplementation( Configuration.getConfigurationSection(ConfigurationSection.uiServer) ) @@ -106,18 +106,27 @@ export class Bootstrap extends EventEmitter { } public get numberOfChargingStationTemplates (): number { - return this.chargingStationsByTemplate.size + return this.templatesChargingStations.size } public get numberOfConfiguredChargingStations (): number { - return [...this.chargingStationsByTemplate.values()].reduce( + return [...this.templatesChargingStations.values()].reduce( (accumulator, value) => accumulator + value.configured, 0 ) } public getLastIndex (templateName: string): number { - return this.chargingStationsByTemplate.get(templateName)?.lastIndex ?? 0 + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const indexes = [...this.templatesChargingStations.get(templateName)!.indexes] + .concat(0) + .sort((a, b) => a - b) + for (let i = 0; i < indexes.length - 1; i++) { + if (indexes[i + 1] - indexes[i] !== 1) { + return indexes[i] + } + } + return indexes[indexes.length - 1] } public getPerformanceStatistics (): IterableIterator | undefined { @@ -125,14 +134,14 @@ export class Bootstrap extends EventEmitter { } private get numberOfAddedChargingStations (): number { - return [...this.chargingStationsByTemplate.values()].reduce( + return [...this.templatesChargingStations.values()].reduce( (accumulator, value) => accumulator + value.added, 0 ) } private get numberOfStartedChargingStations (): number { - return [...this.chargingStationsByTemplate.values()].reduce( + return [...this.templatesChargingStations.values()].reduce( (accumulator, value) => accumulator + value.started, 0 ) @@ -143,6 +152,7 @@ export class Bootstrap extends EventEmitter { 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) @@ -154,7 +164,7 @@ export class Bootstrap extends EventEmitter { ChargingStationWorkerMessageEvents.workerElementError, (eventError: ChargingStationWorkerEventError) => { logger.error( - `${this.logPrefix()} ${moduleName}.messageHandler: Error occurred while handling '${eventError.event}' event on worker:`, + `${this.logPrefix()} ${moduleName}.start: Error occurred while handling '${eventError.event}' event on worker:`, eventError ) } @@ -186,8 +196,8 @@ export class Bootstrap extends EventEmitter { for (const stationTemplateUrl of Configuration.getStationTemplateUrls()!) { try { const nbStations = - this.chargingStationsByTemplate.get(parse(stationTemplateUrl.file).name) - ?.configured ?? stationTemplateUrl.numberOfStations + this.templatesChargingStations.get(parse(stationTemplateUrl.file).name)?.configured ?? + stationTemplateUrl.numberOfStations for (let index = 1; index <= nbStations; index++) { await this.addChargingStation(index, stationTemplateUrl.file) } @@ -299,17 +309,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( @@ -325,7 +336,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 } @@ -349,6 +360,9 @@ export class Bootstrap extends EventEmitter { 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) break @@ -386,8 +400,6 @@ 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 @@ -397,10 +409,27 @@ export class Bootstrap extends EventEmitter { ) } + private readonly workerEventDeleted = (data: ChargingStationData): void => { + this.uiServer?.chargingStations.delete(data.stationInfo.hashId) + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const templateChargingStations = this.templatesChargingStations.get( + data.stationInfo.templateName + )! + --templateChargingStations.added + templateChargingStations.indexes.delete(data.stationInfo.templateIndex) + 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 - ++this.chargingStationsByTemplate.get(data.stationInfo.templateName)!.started + ++this.templatesChargingStations.get(data.stationInfo.templateName)!.started logger.info( `${this.logPrefix()} ${moduleName}.workerEventStarted: Charging station ${ data.stationInfo.chargingStationId @@ -413,7 +442,7 @@ export class Bootstrap extends EventEmitter { private readonly workerEventStopped = (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)!.started + --this.templatesChargingStations.get(data.stationInfo.templateName)!.started logger.info( `${this.logPrefix()} ${moduleName}.workerEventStopped: Charging station ${ data.stationInfo.chargingStationId @@ -449,15 +478,15 @@ export class Bootstrap extends EventEmitter { if (isNotEmptyArray(stationTemplateUrls)) { for (const stationTemplateUrl of stationTemplateUrls) { const templateName = parse(stationTemplateUrl.file).name - this.chargingStationsByTemplate.set(templateName, { + this.templatesChargingStations.set(templateName, { configured: stationTemplateUrl.numberOfStations, added: 0, started: 0, - lastIndex: 0 + indexes: new Set() }) this.uiServer?.chargingStationTemplates.add(templateName) } - if (this.chargingStationsByTemplate.size !== stationTemplateUrls.length) { + if (this.templatesChargingStations.size !== stationTemplateUrls.length) { console.error( chalk.red( "'stationTemplateUrls' contains duplicate entries, please check your configuration" @@ -487,7 +516,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( @@ -495,13 +528,15 @@ 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( - index, - this.chargingStationsByTemplate.get(parse(stationTemplateFile).name)?.lastIndex ?? -Infinity - ) + const templateChargingStations = this.templatesChargingStations.get( + parse(stationTemplateFile).name + )! + ++templateChargingStations.added + templateChargingStations.indexes.add(index) } private gracefulShutdown (): void {