@mdf.js/service-registry
Version:
MMS - API - Service Registry
157 lines • 6.46 kB
JavaScript
"use strict";
/**
* Copyright 2024 Mytra Control S.L. All rights reserved.
*
* Use of this source code is governed by an MIT-style license that can be found in the LICENSE file
* or at https://opensource.org/licenses/MIT.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.HealthFacade = void 0;
const tslib_1 = require("tslib");
const logger_1 = require("@mdf.js/logger");
const cluster_1 = tslib_1.__importDefault(require("cluster"));
const events_1 = require("events");
const Aggregator_1 = require("./Aggregator");
const Ports_1 = require("./Ports");
const Router_1 = require("./Router");
const types_1 = require("./types");
/**
* The HealthFacade class serves as a comprehensive solution for monitoring and exposing the health
* of all components within an application. It abstracts the complexity of health information
* aggregation and distribution, making it accessible through a REST API and manageable across
* different operational contexts (e.g., standalone, clustered master, and worker processes).
*
* This class leverages:
* - Aggregator: To aggregate health checks and status events from components.
* - Port: To handle health information requests and responses in a cluster, accommodating both
* master and worker roles.
* - Router: To expose aggregated health information via a REST API.
*/
class HealthFacade extends events_1.EventEmitter {
/**
* Create an instance of health registry
* @param options - health registry options
*/
constructor(options) {
super();
this.options = options;
/** Event handler for status event */
this.statusEventHandler = () => {
if (this.listenerCount('status') > 0) {
this.emit('status', this.status);
}
};
this.logger = (0, logger_1.SetContext)(
// Stryker disable next-line all
this.options.logger || new logger_1.DebugLogger(`mdf:registry:health:${this.name}`), types_1.HEALTH_SERVICE_NAME, this.options.applicationMetadata.instanceId);
this.aggregator = new Aggregator_1.Aggregator(this.options.applicationMetadata, this.logger);
this.port = this.getPort(this.options, this.aggregator, this.logger);
this._router = new Router_1.Router(this.aggregator);
// Stryker disable next-line all
this.logger.debug(`New health registry instance created`);
}
/**
* Dynamically selects and initializes the appropriate Port implementation based on the
* application's execution context (standalone, clustered master, or worker) to manage
* health information exchange.
* @param options - health registry options
* @param aggregator - health aggregator
* @param logger - logger instance
* @returns Port to manage the health information
*/
getPort(options, aggregator, logger) {
if (typeof options.isCluster === 'boolean') {
return options.isCluster && cluster_1.default.isPrimary
? new Ports_1.MasterPort(aggregator, logger, options.clusterUpdateInterval)
: new Ports_1.WorkerPort(aggregator, logger);
}
return undefined;
}
/** @returns The application name */
get name() {
return this.options.applicationMetadata.name;
}
/** @returns The application identifier */
get componentId() {
return this.options.applicationMetadata.instanceId;
}
/** @returns An Express router with access to health information */
get router() {
return this._router.router;
}
/** @returns Links offered by this service */
get links() {
return { [`${types_1.HEALTH_SERVICE_NAME}`]: `/${types_1.HEALTH_SERVICE_NAME}` };
}
/** @returns The health status of the component */
get status() {
return this.aggregator.status;
}
/** @returns Health checks for this service */
get checks() {
return this.aggregator.checks;
}
/**
* Adds a timestamped note to the health status.
* @param note - Note to be added.
*/
addNote(note) {
this.aggregator.addNote(note);
}
/**
* Register a resource or a list of resources to monitor for errors.
* @param component - Resource or list of resources to be registered
*/
register(component) {
this.aggregator.register(component);
}
/**
* Update or add a check measure.
* This should be used to inform about the state of resources behind the Component/Microservice,
* for example states of connections with field devices.
*
* The new check will be taking into account in the overall health status.
* The new check will be included in the `checks` object with the key "component:measure".
* If this key already exists, the `componentId` of the `check` parameter will be checked, if
* there is a check with the same `componentId` in the array, the check will be updated, in other
* case the new check will be added to the existing array.
*
* The maximum number external checks is 100
* @param component - component identification
* @param measure - measure identification
* @param check - check to be updated or included
* @returns true, if the check has been updated
*/
addCheck(component, measure, check) {
return this.aggregator.addExternalCheck(component, measure, check);
}
/** @returns The health of the application */
get health() {
return this.aggregator.health;
}
/** Start health service */
async start() {
var _a;
// Stryker disable next-line all
this.logger.debug('Starting health registry');
(_a = this.port) === null || _a === void 0 ? void 0 : _a.start();
this.aggregator.on('status', this.statusEventHandler);
}
/** Stop health service */
async stop() {
var _a;
// Stryker disable next-line all
this.logger.debug('Stopping health registry');
(_a = this.port) === null || _a === void 0 ? void 0 : _a.stop();
this.aggregator.off('status', this.statusEventHandler);
}
/** Close health service */
async close() {
// Stryker disable next-line all
this.logger.debug('Closing health registry');
await this.stop();
this.aggregator.close();
}
}
exports.HealthFacade = HealthFacade;
//# sourceMappingURL=HealthFacade.js.map