diff --git a/packages/microservice/src/Microservice.ts b/packages/microservice/src/Microservice.ts index 6f59d10..a8410af 100644 --- a/packages/microservice/src/Microservice.ts +++ b/packages/microservice/src/Microservice.ts @@ -13,6 +13,18 @@ interface InternalServiceMap { */ type InternalServiceConstructor = new (app: T) => InternalService; +/** + * Microservice states + */ +export enum MicroserviceState { + Idling, + Booting, + Starting, + Running, + Quitting, + Finished +} + /** * The main application class */ @@ -24,10 +36,20 @@ export class Microservice private static __instance: Microservice; /** - * All available InternalServices + * A handler function to quit the microservice application + */ + private __quitHandler!: (value: number | PromiseLike) => void; + + /** + * All available services */ protected services: InternalServiceMap = {}; + /** + * The current state of the microservice + */ + protected state: MicroserviceState; + /** * Return the current application instance */ @@ -40,6 +62,7 @@ export class Microservice */ public constructor() { Microservice.__instance = this; + this.state = MicroserviceState.Idling; } // Overridable -------------------------------------------------------------------------------- @@ -52,7 +75,7 @@ export class Microservice // Application Management ---------------------------------------------------------------------- /** - * Boot the application and all of the InternalServices + * Boot the application and all of the services */ protected async boot() { let InternalServices = Object.values(this.services); @@ -71,19 +94,49 @@ export class Microservice * Start the application */ public async exec() { - await this.boot(); - await this.onStart(); - for (let InternalService of Object.values(this.services)) { - InternalService.start(); + // Exit if not in an idling state + if (this.state !== MicroserviceState.Idling) { + return -1; + } + + try { + // Boot the microservice + this.state = MicroserviceState.Booting; + await this.boot(); + + // Start the microservice + this.state = MicroserviceState.Starting + await this.onStart(); + for (let InternalService of Object.values(this.services)) { + InternalService.start(); + } + } catch(e) { + console.log("Failed to start the microservice"); + return 1; } + + // Run the microservice + this.state = MicroserviceState.Running; + let exitCode = await new Promise((resolve) => this.__quitHandler = resolve); + + // Shutdown the microservice + await this.shutdown().catch(() => { + console.log("Error ocurred during shutdown..."); + exitCode = 1; + }); + + // Return the exit code + return exitCode; } /** * Quit the application */ public async quit(code: number = 0) { - await this.shutdown(); - process.exit(code); + if (this.state !== MicroserviceState.Running) { + return; + } + this.__quitHandler(code); } // InternalService Management -------------------------------------------------------------------------- @@ -91,7 +144,7 @@ export class Microservice /** * Install InternalServices into the application */ - protected installServices(this: T, InternalServices: InternalServiceConstructor[]) { + public installServices(this: T, InternalServices: InternalServiceConstructor[]) { for (let InternalServiceClass of InternalServices) { this.installService(InternalServiceClass); } @@ -100,20 +153,20 @@ export class Microservice /** * Install a InternalService into the application */ - protected installService(this: T, InternalServiceClass: InternalServiceConstructor) { + public installService(this: T, InternalServiceClass: InternalServiceConstructor) { let InternalService = new InternalServiceClass(this); this.services[InternalService.name] = InternalService; } /** - * Get all available InternalServices + * Get all available services */ public serviceList() { return Object.keys(this.services); } /** - * Get an application InternalService instance + * Get an application services instance */ public service>(InternalServiceName: string) { assert(InternalServiceName in this.services);