UNPKG

inceptum

Version:

hipages take on the foundational library for enterprise-grade apps written in NodeJS

159 lines 5.68 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const Decorators_1 = require("../ioc/Decorators"); exports.HEALTH_CHECK_GROUP = 'inceptum:health'; function RegisterAsHealthCheck(target) { Decorators_1.RegisterInGroup(exports.HEALTH_CHECK_GROUP)(target); Decorators_1.Lazy(false)(target); } exports.RegisterAsHealthCheck = RegisterAsHealthCheck; var HealthCheckStatus; (function (HealthCheckStatus) { HealthCheckStatus["OK"] = "OK"; HealthCheckStatus["NOT_READY"] = "NOT_READY"; HealthCheckStatus["WARNING"] = "WARNING"; HealthCheckStatus["CRITICAL"] = "CRITICAL"; })(HealthCheckStatus = exports.HealthCheckStatus || (exports.HealthCheckStatus = {})); function getStatusIndex(status) { return [HealthCheckStatus.OK, HealthCheckStatus.NOT_READY, HealthCheckStatus.WARNING, HealthCheckStatus.CRITICAL].indexOf(status); } class HealthCheckResult { constructor(status, message, timestamp, data) { this.status = status; this.message = message; this.data = data; this.timestamp = timestamp || new Date().getTime(); } static getInitialResult() { return new HealthCheckResult(HealthCheckStatus.NOT_READY, 'First check not run yet'); } static staleResult(healthCheck, lastResult) { return new HealthCheckResult(HealthCheckStatus.CRITICAL, `Stale check result for check ${healthCheck.checkName}. Last result on ${lastResult.timestamp}`); } } exports.HealthCheckResult = HealthCheckResult; class HealthCheck { constructor(checkName, sleepMillis = 60000, staleNumFails = 2, runImmediately = false) { this.checkName = checkName; this.sleepMillis = sleepMillis; this.staleNumFails = staleNumFails; this.runImmediately = runImmediately; this.started = false; this.lastResult = HealthCheckResult.getInitialResult(); this.checkRunning = false; } getCheckName() { return this.checkName; } getSleepMillis() { return this.sleepMillis; } start() { if (this.started) { return; } this.started = true; this.doStart(); if (this.runImmediately) { this.runCheck(); } } async runCheck() { if (!this.checkRunning) { this.checkRunning = true; try { this.lastResult = await this.doCheck(); } catch (e) { this.lastResult = new HealthCheckResult(HealthCheckStatus.CRITICAL, `There was an error running check ${this.getCheckName()}: ${e.message}`); } this.checkRunning = false; } } doStart() { this.timer = setInterval(async () => { await this.runCheck(); }, this.getSleepMillis()); } stop() { if (this.started) { this.doStop(); } } doStop() { if (this.timer) { clearInterval(this.timer); } } isStarted() { return this.started; } getLastResult() { const threshold = (new Date().getTime()) - this.getSleepMillis() * this.staleNumFails; if (this.lastResult.timestamp < threshold) { return HealthCheckResult.staleResult(this, this.lastResult); } return this.lastResult; } } exports.HealthCheck = HealthCheck; class HealthCheckGroup extends HealthCheck { constructor(groupName) { super(`Group: ${groupName}`, 0, 0); this.healthChecks = new Map(); this.groupKey = groupName; } addCheck(healthCheck, asName) { this.addCheckAs(healthCheck, asName || healthCheck.getCheckName()); } addCheckAs(healthCheck, asName) { if (asName.indexOf('.') >= 0) { const parts = asName.split('.', 2); const firstPart = parts[0]; const remainderPart = asName.substr(firstPart.length + 1); const group = this.healthChecks.get(firstPart); if (group && (group instanceof HealthCheckGroup)) { group.addCheckAs(healthCheck, remainderPart); } else if (group) { throw new Error(`A health check with name ${firstPart} is already defined in this group`); } else { const newGroup = new HealthCheckGroup(firstPart); newGroup.addCheckAs(healthCheck, remainderPart); this.addCheck(newGroup, firstPart); } } else { this.healthChecks.set(asName, healthCheck); if (this.isStarted()) { healthCheck.start(); } } } doStart() { this.healthChecks.forEach((healthCheck) => { healthCheck.start(); }); } doStop() { this.healthChecks.forEach((healthCheck) => { healthCheck.stop(); }); } async doCheck() { throw new Error('This shouldn\'t be called. We override getLastResult to get up-to-date info'); } getLastResult() { const resp = new HealthCheckResult(HealthCheckStatus.OK, 'OK', new Date().getTime(), {}); this.healthChecks.forEach((healthCheck, key) => { const lastResult = healthCheck.getLastResult(); if (getStatusIndex(lastResult.status) > getStatusIndex(resp.status)) { resp.status = lastResult.status; resp.message = `Check ${healthCheck.getCheckName()} returned ${resp.status}`; } resp.data[key] = lastResult; }); return resp; } } exports.HealthCheckGroup = HealthCheckGroup; //# sourceMappingURL=HealthCheck.js.map