From 25933037ba341ba92eb646101fa75aabe9564cbe Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Benoit?= Date: Tue, 21 Oct 2025 22:47:09 +0200 Subject: [PATCH] perf: emit events only if needed MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérôme Benoit --- .../AutomaticTransactionGenerator.ts | 4 +- src/charging-station/Bootstrap.ts | 56 ++++++++++++++++--- src/charging-station/ChargingStation.ts | 38 ++++++++----- .../ocpp/1.6/OCPP16IncomingRequestService.ts | 6 +- .../ocpp/1.6/OCPP16ResponseService.ts | 6 +- .../ocpp/2.0/OCPP20IncomingRequestService.ts | 6 +- .../ocpp/2.0/OCPP20ResponseService.ts | 6 +- .../ocpp/OCPPRequestService.ts | 4 +- src/charging-station/ocpp/OCPPServiceUtils.ts | 2 +- 9 files changed, 93 insertions(+), 35 deletions(-) diff --git a/src/charging-station/AutomaticTransactionGenerator.ts b/src/charging-station/AutomaticTransactionGenerator.ts index e9d9eba6..8106d29a 100644 --- a/src/charging-station/AutomaticTransactionGenerator.ts +++ b/src/charging-station/AutomaticTransactionGenerator.ts @@ -367,7 +367,7 @@ export class AutomaticTransactionGenerator { `${this.logPrefix(connectorId)} stopped with connector status: %j`, this.connectorsStatus.get(connectorId) ) - this.chargingStation.emit(ChargingStationEvents.updated) + this.chargingStation.emitChargingStationEvent(ChargingStationEvents.updated) } private readonly logPrefix = (connectorId?: number): string => { @@ -406,7 +406,7 @@ export class AutomaticTransactionGenerator { this.connectorsStatus.get(connectorId)!.skippedConsecutiveTransactions = 0 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion this.connectorsStatus.get(connectorId)!.start = true - this.chargingStation.emit(ChargingStationEvents.updated) + this.chargingStation.emitChargingStationEvent(ChargingStationEvents.updated) } private startConnectors (stopAbsoluteDuration?: boolean): void { diff --git a/src/charging-station/Bootstrap.ts b/src/charging-station/Bootstrap.ts index d249efb5..0629ad85 100644 --- a/src/charging-station/Bootstrap.ts +++ b/src/charging-station/Bootstrap.ts @@ -468,27 +468,69 @@ export class Bootstrap extends EventEmitter { const { data, event } = msg try { switch (event) { + case ChargingStationWorkerMessageEvents.accepted: + if (this.listenerCount(ChargingStationWorkerMessageEvents.accepted) > 0) { + this.emit(ChargingStationWorkerMessageEvents.accepted, data) + } + break case ChargingStationWorkerMessageEvents.added: - this.emit(ChargingStationWorkerMessageEvents.added, data) + if (this.listenerCount(ChargingStationWorkerMessageEvents.added) > 0) { + this.emit(ChargingStationWorkerMessageEvents.added, data) + } + break + case ChargingStationWorkerMessageEvents.connected: + if (this.listenerCount(ChargingStationWorkerMessageEvents.connected) > 0) { + this.emit(ChargingStationWorkerMessageEvents.connected, data) + } + break + case ChargingStationWorkerMessageEvents.connectorStatusChanged: + if (this.listenerCount(ChargingStationWorkerMessageEvents.connectorStatusChanged) > 0) { + this.emit(ChargingStationWorkerMessageEvents.connectorStatusChanged, data) + } break case ChargingStationWorkerMessageEvents.deleted: - this.emit(ChargingStationWorkerMessageEvents.deleted, data) + if (this.listenerCount(ChargingStationWorkerMessageEvents.deleted) > 0) { + this.emit(ChargingStationWorkerMessageEvents.deleted, data) + } + break + case ChargingStationWorkerMessageEvents.disconnected: + if (this.listenerCount(ChargingStationWorkerMessageEvents.disconnected) > 0) { + this.emit(ChargingStationWorkerMessageEvents.disconnected, data) + } + break + case ChargingStationWorkerMessageEvents.pending: + if (this.listenerCount(ChargingStationWorkerMessageEvents.pending) > 0) { + this.emit(ChargingStationWorkerMessageEvents.pending, data) + } break case ChargingStationWorkerMessageEvents.performanceStatistics: - this.emit(ChargingStationWorkerMessageEvents.performanceStatistics, data) + if (this.listenerCount(ChargingStationWorkerMessageEvents.performanceStatistics) > 0) { + this.emit(ChargingStationWorkerMessageEvents.performanceStatistics, data) + } + break + case ChargingStationWorkerMessageEvents.rejected: + if (this.listenerCount(ChargingStationWorkerMessageEvents.rejected) > 0) { + this.emit(ChargingStationWorkerMessageEvents.rejected, data) + } break case ChargingStationWorkerMessageEvents.started: - this.emit(ChargingStationWorkerMessageEvents.started, data) + if (this.listenerCount(ChargingStationWorkerMessageEvents.started) > 0) { + this.emit(ChargingStationWorkerMessageEvents.started, data) + } break case ChargingStationWorkerMessageEvents.stopped: - this.emit(ChargingStationWorkerMessageEvents.stopped, data) + if (this.listenerCount(ChargingStationWorkerMessageEvents.stopped) > 0) { + this.emit(ChargingStationWorkerMessageEvents.stopped, data) + } break case ChargingStationWorkerMessageEvents.updated: - this.emit(ChargingStationWorkerMessageEvents.updated, data) + if (this.listenerCount(ChargingStationWorkerMessageEvents.updated) > 0) { + this.emit(ChargingStationWorkerMessageEvents.updated, data) + } break default: throw new BaseError( - `Unknown charging station worker message event: '${event}' received with data: ${JSON.stringify( + `Unknown charging station worker message event: '${event as string}' received with data: ${JSON.stringify( data, undefined, 2 diff --git a/src/charging-station/ChargingStation.ts b/src/charging-station/ChargingStation.ts index 4c559611..721d8625 100644 --- a/src/charging-station/ChargingStation.ts +++ b/src/charging-station/ChargingStation.ts @@ -329,10 +329,22 @@ export class ChargingStation extends EventEmitter { this.templateFileWatcher?.unref() deleteConfiguration && rmSync(this.configurationFile, { force: true }) this.chargingStationWorkerBroadcastChannel.unref() - this.emit(ChargingStationEvents.deleted) + this.emitChargingStationEvent(ChargingStationEvents.deleted) this.removeAllListeners() } + /** + * Emit a ChargingStation event only if there are listeners registered for it. + * This optimizes performance by avoiding unnecessary event emission. + * @param event - The ChargingStation event to emit + * @param args - Arguments to pass to the event listeners + */ + public emitChargingStationEvent (event: ChargingStationEvents, ...args: unknown[]): void { + if (this.listenerCount(event) > 0) { + this.emit(event, ...args) + } + } + public getAuthorizeRemoteTxRequests (): boolean { const authorizeRemoteTxRequests = getConfigurationKey( this, @@ -863,7 +875,7 @@ export class ChargingStation extends EventEmitter { } ) this.started = true - this.emit(ChargingStationEvents.started) + this.emitChargingStationEvent(ChargingStationEvents.started) this.starting = false } else { logger.warn(`${this.logPrefix()} Charging station is already starting...`) @@ -886,7 +898,7 @@ export class ChargingStation extends EventEmitter { this.automaticTransactionGenerator?.start(stopAbsoluteDuration) } this.saveAutomaticTransactionGeneratorConfiguration() - this.emit(ChargingStationEvents.updated) + this.emitChargingStationEvent(ChargingStationEvents.updated) } public startHeartbeat (): void { @@ -1001,7 +1013,7 @@ export class ChargingStation extends EventEmitter { this.started = false this.saveConfiguration() this.sharedLRUCache.deleteChargingStationConfiguration(this.configurationFileHash) - this.emit(ChargingStationEvents.stopped) + this.emitChargingStationEvent(ChargingStationEvents.stopped) this.stopping = false } else { logger.warn(`${this.logPrefix()} Charging station is already stopping...`) @@ -1020,7 +1032,7 @@ export class ChargingStation extends EventEmitter { this.automaticTransactionGenerator?.stop() } this.saveAutomaticTransactionGeneratorConfiguration() - this.emit(ChargingStationEvents.updated) + this.emitChargingStationEvent(ChargingStationEvents.updated) } public stopMeterValues (connectorId: number): void { @@ -1066,7 +1078,7 @@ export class ChargingStation extends EventEmitter { } private add (): void { - this.emit(ChargingStationEvents.added) + this.emitChargingStationEvent(ChargingStationEvents.added) } private clearIntervalFlushMessageBuffer (): void { @@ -1481,7 +1493,7 @@ export class ChargingStation extends EventEmitter { commandName, commandPayload ) - this.emit(ChargingStationEvents.updated) + this.emitChargingStationEvent(ChargingStationEvents.updated) } private handleResponseMessage (response: Response): void { @@ -1918,8 +1930,8 @@ export class ChargingStation extends EventEmitter { } private onClose (code: WebSocketCloseEventStatusCode, reason: Buffer): void { - this.emit(ChargingStationEvents.disconnected) - this.emit(ChargingStationEvents.updated) + this.emitChargingStationEvent(ChargingStationEvents.disconnected) + this.emitChargingStationEvent(ChargingStationEvents.updated) switch (code) { // Normal close case WebSocketCloseEventStatusCode.CLOSE_NO_STATUS: @@ -1941,7 +1953,7 @@ export class ChargingStation extends EventEmitter { this.started && this.reconnect() .then(() => { - this.emit(ChargingStationEvents.updated) + this.emitChargingStationEvent(ChargingStationEvents.updated) return undefined }) .catch((error: unknown) => @@ -2052,8 +2064,8 @@ export class ChargingStation extends EventEmitter { private async onOpen (): Promise { if (this.isWebSocketConnectionOpened()) { - this.emit(ChargingStationEvents.connected) - this.emit(ChargingStationEvents.updated) + this.emitChargingStationEvent(ChargingStationEvents.connected) + this.emitChargingStationEvent(ChargingStationEvents.updated) logger.info( `${this.logPrefix()} Connection to OCPP server through ${ this.wsConnectionUrl.href @@ -2097,7 +2109,7 @@ export class ChargingStation extends EventEmitter { `${this.logPrefix()} Registration failure: maximum retries reached (${registrationRetryCount.toString()}) or retry disabled (${this.stationInfo?.registrationMaxRetries?.toString()})` ) } - this.emit(ChargingStationEvents.updated) + this.emitChargingStationEvent(ChargingStationEvents.updated) } else { logger.warn( `${this.logPrefix()} Connection to OCPP server through ${this.wsConnectionUrl.href} failed` diff --git a/src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts b/src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts index 8b530e2a..5e7a4a6b 100644 --- a/src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts +++ b/src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts @@ -655,8 +655,10 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { response, commandName ) - // Emit command name event to allow delayed handling - this.emit(commandName, chargingStation, commandPayload, response) + // Emit command name event to allow delayed handling only if there are listeners + if (this.listenerCount(commandName) > 0) { + this.emit(commandName, chargingStation, commandPayload, response) + } } private async handleRequestCancelReservation ( diff --git a/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts b/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts index 871249c5..0921078b 100644 --- a/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts +++ b/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts @@ -526,11 +526,11 @@ export class OCPP16ResponseService extends OCPPResponseService { ) } if (chargingStation.inAcceptedState()) { - chargingStation.emit(ChargingStationEvents.accepted) + chargingStation.emitChargingStationEvent(ChargingStationEvents.accepted) } else if (chargingStation.inPendingState()) { - chargingStation.emit(ChargingStationEvents.pending) + chargingStation.emitChargingStationEvent(ChargingStationEvents.pending) } else if (chargingStation.inRejectedState()) { - chargingStation.emit(ChargingStationEvents.rejected) + chargingStation.emitChargingStationEvent(ChargingStationEvents.rejected) } const logMsg = `${chargingStation.logPrefix()} Charging station in '${ payload.status diff --git a/src/charging-station/ocpp/2.0/OCPP20IncomingRequestService.ts b/src/charging-station/ocpp/2.0/OCPP20IncomingRequestService.ts index c77014e0..572fc211 100644 --- a/src/charging-station/ocpp/2.0/OCPP20IncomingRequestService.ts +++ b/src/charging-station/ocpp/2.0/OCPP20IncomingRequestService.ts @@ -180,8 +180,10 @@ export class OCPP20IncomingRequestService extends OCPPIncomingRequestService { response, commandName ) - // Emit command name event to allow delayed handling - this.emit(commandName, chargingStation, commandPayload, response) + // Emit command name event to allow delayed handling only if there are listeners + if (this.listenerCount(commandName) > 0) { + this.emit(commandName, chargingStation, commandPayload, response) + } } private buildReportData ( diff --git a/src/charging-station/ocpp/2.0/OCPP20ResponseService.ts b/src/charging-station/ocpp/2.0/OCPP20ResponseService.ts index c092059f..ec76b2f8 100644 --- a/src/charging-station/ocpp/2.0/OCPP20ResponseService.ts +++ b/src/charging-station/ocpp/2.0/OCPP20ResponseService.ts @@ -204,11 +204,11 @@ export class OCPP20ResponseService extends OCPPResponseService { ) } if (chargingStation.inAcceptedState()) { - chargingStation.emit(ChargingStationEvents.accepted) + chargingStation.emitChargingStationEvent(ChargingStationEvents.accepted) } else if (chargingStation.inPendingState()) { - chargingStation.emit(ChargingStationEvents.pending) + chargingStation.emitChargingStationEvent(ChargingStationEvents.pending) } else if (chargingStation.inRejectedState()) { - chargingStation.emit(ChargingStationEvents.rejected) + chargingStation.emitChargingStationEvent(ChargingStationEvents.rejected) } const logMsg = `${chargingStation.logPrefix()} Charging station in '${ payload.status diff --git a/src/charging-station/ocpp/OCPPRequestService.ts b/src/charging-station/ocpp/OCPPRequestService.ts index 439d656f..d5b944f1 100644 --- a/src/charging-station/ocpp/OCPPRequestService.ts +++ b/src/charging-station/ocpp/OCPPRequestService.ts @@ -282,7 +282,7 @@ export abstract class OCPPRequestService { }) .finally(() => { chargingStation.requests.delete(messageId) - chargingStation.emit(ChargingStationEvents.updated) + chargingStation.emitChargingStationEvent(ChargingStationEvents.updated) }) .catch(reject) } @@ -307,7 +307,7 @@ export abstract class OCPPRequestService { ocppError ) chargingStation.requests.delete(messageId) - chargingStation.emit(ChargingStationEvents.updated) + chargingStation.emitChargingStationEvent(ChargingStationEvents.updated) reject(ocppError) } diff --git a/src/charging-station/ocpp/OCPPServiceUtils.ts b/src/charging-station/ocpp/OCPPServiceUtils.ts index c7ccb905..36d66fcb 100644 --- a/src/charging-station/ocpp/OCPPServiceUtils.ts +++ b/src/charging-station/ocpp/OCPPServiceUtils.ts @@ -192,7 +192,7 @@ export const sendAndSetConnectorStatus = async ( ) } connectorStatus.status = status - chargingStation.emit(ChargingStationEvents.connectorStatusChanged, { + chargingStation.emitChargingStationEvent(ChargingStationEvents.connectorStatusChanged, { connectorId, ...connectorStatus, }) -- 2.53.0