From: Jérôme Benoit Date: Thu, 25 May 2023 22:02:19 +0000 (+0200) Subject: feat: add graceful shutdown X-Git-Tag: v1.2.14~8 X-Git-Url: https://git.piment-noir.org/?a=commitdiff_plain;ds=sidebyside;h=6bd808fd1dc554c8d55521b20a064447835ef04c;p=e-mobility-charging-stations-simulator.git feat: add graceful shutdown Signed-off-by: Jérôme Benoit --- diff --git a/src/charging-station/Bootstrap.ts b/src/charging-station/Bootstrap.ts index 33122242..4a6bd75c 100644 --- a/src/charging-station/Bootstrap.ts +++ b/src/charging-station/Bootstrap.ts @@ -17,10 +17,11 @@ import { type ChargingStationWorkerMessage, type ChargingStationWorkerMessageData, ChargingStationWorkerMessageEvents, + ProcedureName, type StationTemplateUrl, type Statistics, } from '../types'; -import { Configuration, ErrorUtils, Utils, logger } from '../utils'; +import { Configuration, Constants, ErrorUtils, Utils, logger } from '../utils'; import { type MessageHandler, type WorkerAbstract, WorkerFactory } from '../worker'; const moduleName = 'Bootstrap'; @@ -44,6 +45,11 @@ export class Bootstrap { private readonly workerScript: string; private constructor() { + for (const signal of ['SIGINT', 'SIGQUIT', 'SIGTERM']) { + process.on(signal, () => { + this.gracefulShutdown().catch(Constants.EMPTY_FUNCTION); + }); + } // Enable unconditionally for now ErrorUtils.handleUnhandledRejection(); ErrorUtils.handleUncaughtException(); @@ -123,6 +129,11 @@ export class Bootstrap { public async stop(): Promise { if (isMainThread && this.started === true) { + await this.uiServer?.sendBroadcastChannelRequest( + Utils.generateUUID(), + ProcedureName.STOP_CHARGING_STATION, + Constants.EMPTY_FREEZED_OBJECT + ); await this.workerImplementation?.stop(); this.workerImplementation = null; this.uiServer?.stop(); @@ -271,6 +282,16 @@ export class Bootstrap { }); } + private gracefulShutdown = async (): Promise => { + console.info(`${chalk.green('Graceful shutdown')}`); + try { + await this.stop(); + process.exit(0); + } catch (error) { + process.exit(1); + } + }; + private logPrefix = (): string => { return Utils.logPrefix(' Bootstrap |'); }; diff --git a/src/charging-station/ChargingStationWorker.ts b/src/charging-station/ChargingStationWorker.ts index 24ee468c..60d06564 100644 --- a/src/charging-station/ChargingStationWorker.ts +++ b/src/charging-station/ChargingStationWorker.ts @@ -35,7 +35,6 @@ export let threadWorker: ThreadWorker; if (Configuration.workerPoolInUse()) { threadWorker = new ThreadWorker(startChargingStation, { maxInactiveTime: WorkerConstants.POOL_MAX_INACTIVE_TIME, - async: false, }); } else { // Add message listener to start charging station from main thread diff --git a/src/charging-station/ui-server/AbstractUIServer.ts b/src/charging-station/ui-server/AbstractUIServer.ts index 643b1883..2f6f950b 100644 --- a/src/charging-station/ui-server/AbstractUIServer.ts +++ b/src/charging-station/ui-server/AbstractUIServer.ts @@ -46,6 +46,16 @@ export abstract class AbstractUIServer { this.chargingStations.clear(); } + public async sendBroadcastChannelRequest( + id: string, + procedureName: ProcedureName, + requestPayload: RequestPayload + ): Promise { + for (const uiService of this.uiServices.values()) { + await uiService.requestHandler(this.buildProtocolRequest(id, procedureName, requestPayload)); + } + } + protected startHttpServer(): void { if (this.httpServer.listening === false) { this.httpServer.listen(this.uiServerConfiguration.options); diff --git a/src/charging-station/ui-server/ui-services/AbstractUIService.ts b/src/charging-station/ui-server/ui-services/AbstractUIService.ts index 71b057ab..541966af 100644 --- a/src/charging-station/ui-server/ui-services/AbstractUIService.ts +++ b/src/charging-station/ui-server/ui-services/AbstractUIService.ts @@ -87,7 +87,7 @@ export abstract class AbstractUIService { responsePayload = await this.requestHandlers.get(command)(messageId, command, requestPayload); } catch (error) { // Log - logger.error(`${this.logPrefix(moduleName, 'messageHandler')} Handle request error:`, error); + logger.error(`${this.logPrefix(moduleName, 'requestHandler')} Handle request error:`, error); responsePayload = { hashIds: requestPayload?.hashIds, status: ResponseStatus.FAILURE, diff --git a/src/worker/WorkerUtils.ts b/src/worker/WorkerUtils.ts index 7c72ff3e..943de290 100644 --- a/src/worker/WorkerUtils.ts +++ b/src/worker/WorkerUtils.ts @@ -10,8 +10,12 @@ export class WorkerUtils { } public static defaultExitHandler = (code: number): void => { - if (code !== 0) { - console.error(chalk.red(`Worker exited with error exit code: ${code.toString()}`)); + if (code === 0) { + console.info(chalk.green('Worker exited successfully')); + } else if (code === 1) { + console.info(chalk.green('Worker terminated successfully')); + } else if (code > 1) { + console.error(chalk.red(`Worker exited with exit code: ${code.toString()}`)); } };