feat: add graceful shutdown
[e-mobility-charging-stations-simulator.git] / src / charging-station / Bootstrap.ts
index 3312224278521fe7e98fc128b58c2ad5bc887fb6..4a6bd75c2d7a2ebbce2e6ebb24c3ceab9019dba6 100644 (file)
@@ -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<void> {
     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<void> => {
+    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 |');
   };