UNPKG

@qrvey/health-checker

Version:

![install size](https://packagephobia.com/badge?p=@qrvey/health-checker) ![coverage](https://img.shields.io/badge/unit_test_coverage-87%25-brightgreen)

151 lines 6.55 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.handleRuntimeHealth = void 0; exports.createRuntimeHealthMiddlewareCacheState = createRuntimeHealthMiddlewareCacheState; const runtimeHealth_service_1 = require("../../services/runtimeHealth.service"); const constants_1 = require("../../utils/constants"); const runtimeHealth_constants_1 = require("../../utils/runtimeHealth.constants"); const runtimeHealth_constants_2 = require("../../utils/runtimeHealth.constants"); const logger_1 = __importDefault(require("../../utils/logger")); const handleRuntimeHealth = async (req, res, options, cache) => { if (req.method === constants_1.HTTP_METHOD_OPTIONS) { return true; } const resolvedOptions = resolveStartOptions(options); if (!isRequestTargeted(req, resolvedOptions)) { return true; } try { const result = await getRuntimeHealthStatusWithCache(resolvedOptions.runtimeOptions, resolvedOptions.cacheTtlMs, cache); if (result.status === constants_1.FAILED) { const cacheLog = runtimeHealth_constants_1.DEFAULT_RUNTIME_HEALTH_LOG_GET && result.details.cache ? { cache: result.details.cache } : {}; logger_1.default.warn('[RuntimeHealthMiddleware] RuntimeHealth is unhealthy', Object.assign({ path: req.path, method: req.method, failedMetrics: result.details.failedMetrics }, cacheLog)); res.sendJson(constants_1.HTTP_STATUS_TOO_MANY_REQUESTS, result); return false; } if (runtimeHealth_constants_1.DEFAULT_RUNTIME_HEALTH_LOG_GET && result.details.cache && result.details.cache.source !== runtimeHealth_constants_2.RUNTIME_HEALTH_CACHE_SOURCE.computed) { logger_1.default.info('[RuntimeHealthMiddleware] RuntimeHealth from cache', { path: req.path, method: req.method, cache: result.details.cache, }); } return true; } catch (err) { logger_1.default.error('[RuntimeHealthMiddleware] RuntimeHealth check failed', { error: err instanceof Error ? err.message : String(err), path: req.path, method: req.method, }); res.sendJson(constants_1.HTTP_STATUS_TOO_MANY_REQUESTS, { status: constants_1.FAILED, details: { reason: constants_1.RUNTIME_HEALTH_ERROR_REASON }, }); return false; } }; exports.handleRuntimeHealth = handleRuntimeHealth; function createRuntimeHealthMiddlewareCacheState() { return {}; } function isRequestTargeted(req, resolvedOptions) { if (resolvedOptions.serviceNames.length === 0) { return true; } const serviceName = getHeaderValue(req.headers, resolvedOptions.serviceNameHeader); return !!serviceName && resolvedOptions.serviceNames.includes(serviceName); } function resolveStartOptions(options) { var _a, _b, _c, _d; if (!options) { return { runtimeOptions: undefined, serviceNames: [], serviceNameHeader: constants_1.DEFAULT_SERVICE_NAME_HEADER, cacheTtlMs: runtimeHealth_constants_1.DEFAULT_RUNTIME_HEALTH_CACHE_TTL_MS, }; } if (isRuntimeHealthMiddlewareStartOptions(options)) { return { runtimeOptions: options.runtimeOptions, serviceNames: (_a = options.serviceNames) !== null && _a !== void 0 ? _a : [], serviceNameHeader: (_c = (_b = options.serviceNameHeader) === null || _b === void 0 ? void 0 : _b.toLowerCase()) !== null && _c !== void 0 ? _c : constants_1.DEFAULT_SERVICE_NAME_HEADER, cacheTtlMs: (_d = options.cacheTtlMs) !== null && _d !== void 0 ? _d : runtimeHealth_constants_1.DEFAULT_RUNTIME_HEALTH_CACHE_TTL_MS, }; } return { runtimeOptions: options, serviceNames: [], serviceNameHeader: constants_1.DEFAULT_SERVICE_NAME_HEADER, cacheTtlMs: runtimeHealth_constants_1.DEFAULT_RUNTIME_HEALTH_CACHE_TTL_MS, }; } function isRuntimeHealthMiddlewareStartOptions(options) { return ('runtimeOptions' in options || 'serviceNames' in options || 'serviceNameHeader' in options || 'cacheTtlMs' in options); } function getHeaderValue(headers, headerName) { const value = headers[headerName]; if (Array.isArray(value)) { return value[0]; } return typeof value === 'string' ? value : undefined; } async function getRuntimeHealthStatusWithCache(runtimeOptions, cacheTtlMs, cache = {}) { const now = Date.now(); if (isCacheValid(cache, now, cacheTtlMs)) { return withCacheInfo(cache.cachedStatus, { source: runtimeHealth_constants_2.RUNTIME_HEALTH_CACHE_SOURCE.cached, ttlMs: cacheTtlMs, ageMs: now - cache.cachedAtMs, cachedAt: toISOStringOrUndefined(cache.cachedAtMs), }); } if (cache.inFlight) { const status = await cache.inFlight; return withCacheInfo(status, { source: runtimeHealth_constants_2.RUNTIME_HEALTH_CACHE_SOURCE.in_flight, ttlMs: cacheTtlMs, ageMs: cache.cachedAtMs != null ? Date.now() - cache.cachedAtMs : 0, cachedAt: toISOStringOrUndefined(cache.cachedAtMs), }); } cache.inFlight = runtimeHealth_service_1.RuntimeHealthService.get(runtimeOptions) .then((status) => { cache.cachedStatus = status; cache.cachedAtMs = Date.now(); return status; }) .finally(() => { cache.inFlight = undefined; }); const status = await cache.inFlight; return withCacheInfo(status, { source: runtimeHealth_constants_2.RUNTIME_HEALTH_CACHE_SOURCE.computed, ttlMs: cacheTtlMs, ageMs: 0, cachedAt: toISOStringOrUndefined(cache.cachedAtMs), }); } function isCacheValid(cache, now, cacheTtlMs) { return (cache.cachedStatus != null && cache.cachedAtMs != null && now - cache.cachedAtMs < cacheTtlMs); } function toISOStringOrUndefined(ms) { return ms != null ? new Date(ms).toISOString() : undefined; } function withCacheInfo(status, cacheInfo) { return Object.assign(Object.assign({}, status), { details: Object.assign(Object.assign({}, status.details), { cache: cacheInfo }) }); } //# sourceMappingURL=runtimeHealth.middleware.js.map