@adalo/metrics 0.1.130 → 0.1.131
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/health/healthCheckCache.d.ts.map +1 -1
- package/lib/health/healthCheckCache.js +1 -13
- package/lib/health/healthCheckCache.js.map +1 -1
- package/lib/health/healthCheckClient.d.ts +117 -243
- package/lib/health/healthCheckClient.d.ts.map +1 -1
- package/lib/health/healthCheckClient.js +156 -451
- package/lib/health/healthCheckClient.js.map +1 -1
- package/lib/health/healthCheckUtils.d.ts +27 -30
- package/lib/health/healthCheckUtils.d.ts.map +1 -1
- package/lib/health/healthCheckUtils.js +68 -43
- package/lib/health/healthCheckUtils.js.map +1 -1
- package/lib/health/healthCheckWorker.d.ts.map +1 -1
- package/lib/health/healthCheckWorker.js +12 -15
- package/lib/health/healthCheckWorker.js.map +1 -1
- package/package.json +1 -1
- package/src/health/healthCheckCache.js +1 -10
- package/src/health/healthCheckClient.js +134 -433
- package/src/health/healthCheckUtils.js +71 -43
- package/src/health/healthCheckWorker.js +16 -16
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"healthCheckCache.d.ts","sourceRoot":"","sources":["../../src/health/healthCheckCache.js"],"names":[],"mappings":"AAOA;;;;GAIG;AACH;IACE;;;;;OAKG;IACH;QAJyB,WAAW,GAAzB,GAAG;QACc,OAAO;QACP,UAAU;OAsBrC;IAnBC,iBAA8C;IAC9C,gBACgE;IAChE,
|
|
1
|
+
{"version":3,"file":"healthCheckCache.d.ts","sourceRoot":"","sources":["../../src/health/healthCheckCache.js"],"names":[],"mappings":"AAOA;;;;GAIG;AACH;IACE;;;;;OAKG;IACH;QAJyB,WAAW,GAAzB,GAAG;QACc,OAAO;QACP,UAAU;OAsBrC;IAnBC,iBAA8C;IAC9C,gBACgE;IAChE,mBAA8C;IAC9C,iBAA6C;IAE7C,+BAA+B;IAC/B,kBAAwB;IACxB,2BAAiC;IAG/B,qCAA4D;IAC5D,yBAA2B;IAS/B;;;;OAIG;IACH,6BAgCC;IAED;;;;;OAKG;IACH,OAHa,QAAQ,MAAM,GAAG,IAAI,CAAC,CAsDlC;IAED;;;;OAIG;IACH,YAHW,MAAM,GACJ,QAAQ,IAAI,CAAC,CAqCzB;IAED;;;OAGG;IACH,SAFa,QAAQ,IAAI,CAAC,CAyBzB;IAED;;;OAGG;IACH,oBAFa,OAAO,CAInB;CACF"}
|
|
@@ -22,7 +22,7 @@ class HealthCheckCache {
|
|
|
22
22
|
constructor(options = {}) {
|
|
23
23
|
this.redisClient = options.redisClient || null;
|
|
24
24
|
this.appName = options.appName || process.env.BUILD_APP_NAME || 'unknown-app';
|
|
25
|
-
this.cacheTtlMs = options.cacheTtlMs ??
|
|
25
|
+
this.cacheTtlMs = options.cacheTtlMs ?? 60_000;
|
|
26
26
|
this.cacheKey = `healthcheck:${this.appName}`;
|
|
27
27
|
|
|
28
28
|
/** In-memory fallback cache */
|
|
@@ -61,7 +61,6 @@ class HealthCheckCache {
|
|
|
61
61
|
}
|
|
62
62
|
return pong === 'PONG';
|
|
63
63
|
} catch (err) {
|
|
64
|
-
// Redis not available
|
|
65
64
|
if (this._redisAvailable) {
|
|
66
65
|
console.warn(`[HealthCheckCache] Redis became unavailable: ${err.message}`);
|
|
67
66
|
this._redisAvailable = false;
|
|
@@ -77,7 +76,6 @@ class HealthCheckCache {
|
|
|
77
76
|
* @throws {Error} If Redis is configured but read fails
|
|
78
77
|
*/
|
|
79
78
|
async get() {
|
|
80
|
-
// If Redis is configured, we MUST read from it (don't fall back to memory)
|
|
81
79
|
if (this.redisClient) {
|
|
82
80
|
try {
|
|
83
81
|
let cachedStr;
|
|
@@ -96,7 +94,6 @@ class HealthCheckCache {
|
|
|
96
94
|
if (cached.result && cached.timestamp) {
|
|
97
95
|
const age = Date.now() - cached.timestamp;
|
|
98
96
|
if (age < this.cacheTtlMs) {
|
|
99
|
-
// Also update in-memory cache as backup
|
|
100
97
|
this._memoryCache = cached.result;
|
|
101
98
|
this._memoryCacheTimestamp = cached.timestamp;
|
|
102
99
|
return cached.result;
|
|
@@ -106,16 +103,12 @@ class HealthCheckCache {
|
|
|
106
103
|
console.warn(`[HealthCheckCache] Failed to parse Redis cache:`, parseErr.message);
|
|
107
104
|
}
|
|
108
105
|
}
|
|
109
|
-
// No cache in Redis - return null (worker may not have run yet)
|
|
110
106
|
return null;
|
|
111
107
|
} catch (redisErr) {
|
|
112
|
-
// Redis read failed - throw error so caller can return proper error format
|
|
113
108
|
this._redisAvailable = false;
|
|
114
109
|
throw new Error(`Redis cache read failed: ${redisErr.message}`);
|
|
115
110
|
}
|
|
116
111
|
}
|
|
117
|
-
|
|
118
|
-
// No Redis configured - fall back to in-memory cache
|
|
119
112
|
if (this._memoryCache && this._memoryCacheTimestamp) {
|
|
120
113
|
const age = Date.now() - this._memoryCacheTimestamp;
|
|
121
114
|
if (age < this.cacheTtlMs) {
|
|
@@ -135,12 +128,8 @@ class HealthCheckCache {
|
|
|
135
128
|
result,
|
|
136
129
|
timestamp: Date.now()
|
|
137
130
|
};
|
|
138
|
-
|
|
139
|
-
// Update in-memory cache
|
|
140
131
|
this._memoryCache = result;
|
|
141
132
|
this._memoryCacheTimestamp = cacheData.timestamp;
|
|
142
|
-
|
|
143
|
-
// Try to update Redis if available
|
|
144
133
|
if (await this._checkRedisAvailable()) {
|
|
145
134
|
try {
|
|
146
135
|
const cacheStr = JSON.stringify(cacheData);
|
|
@@ -155,7 +144,6 @@ class HealthCheckCache {
|
|
|
155
144
|
await this.redisClient.setex(this.cacheKey, ttlSeconds, cacheStr);
|
|
156
145
|
}
|
|
157
146
|
} catch (redisErr) {
|
|
158
|
-
// Redis write failed, but in-memory cache is updated
|
|
159
147
|
console.warn(`[HealthCheckCache] Redis write failed (in-memory cache updated):`, redisErr.message);
|
|
160
148
|
this._redisAvailable = false;
|
|
161
149
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"healthCheckCache.js","names":["getRedisClientType","REDIS_V4","IOREDIS","REDIS_V3","require","HealthCheckCache","constructor","options","redisClient","appName","process","env","BUILD_APP_NAME","cacheTtlMs","cacheKey","_memoryCache","_memoryCacheTimestamp","_redisClientType","_redisAvailable","console","warn","_checkRedisAvailable","pong","Promise","resolve","reject","ping","err","result","message","get","cachedStr","cached","JSON","parse","timestamp","age","Date","now","parseErr","redisErr","Error","set","cacheData","cacheStr","stringify","ttlSeconds","Math","ceil","setex","clear","del","isRedisAvailable","module","exports"],"sources":["../../src/health/healthCheckCache.js"],"sourcesContent":["const {\n getRedisClientType,\n REDIS_V4,\n IOREDIS,\n REDIS_V3,\n} = require('../redisUtils')\n\n/**\n * HealthCheckCache provides a shared cache layer for health check results.\n * It uses Redis if available for cross-process sharing, with graceful fallback\n * to in-memory cache if Redis is not configured or unavailable.\n */\nclass HealthCheckCache {\n /**\n * @param {Object} options\n * @param {any} [options.redisClient] - Redis client instance (optional)\n * @param {string} [options.appName] - Application name for cache key\n * @param {number} [options.cacheTtlMs=60000] - Cache TTL in milliseconds\n */\n constructor(options = {}) {\n this.redisClient = options.redisClient || null\n this.appName =\n options.appName || process.env.BUILD_APP_NAME || 'unknown-app'\n this.cacheTtlMs = options.cacheTtlMs ?? 60 * 1000\n this.cacheKey = `healthcheck:${this.appName}`\n\n /** In-memory fallback cache */\n this._memoryCache = null\n this._memoryCacheTimestamp = null\n\n if (this.redisClient) {\n this._redisClientType = getRedisClientType(this.redisClient)\n this._redisAvailable = true\n } else {\n this._redisAvailable = false\n console.warn(\n `[HealthCheckCache] Redis not configured for ${this.appName}, using in-memory cache only (not shared across processes)`\n )\n }\n }\n\n /**\n * Checks if Redis is available and working.\n * @returns {Promise<boolean>}\n * @private\n */\n async _checkRedisAvailable() {\n if (!this.redisClient || !this._redisAvailable) {\n return false\n }\n\n try {\n let pong\n if (this._redisClientType === REDIS_V3) {\n pong = await new Promise((resolve, reject) => {\n this.redisClient.ping((err, result) => {\n if (err) reject(err)\n else resolve(result)\n })\n })\n } else if (\n this._redisClientType === REDIS_V4 ||\n this._redisClientType === IOREDIS\n ) {\n pong = await this.redisClient.ping()\n } else {\n return false\n }\n return pong === 'PONG'\n } catch (err) {\n // Redis not available\n if (this._redisAvailable) {\n console.warn(\n `[HealthCheckCache] Redis became unavailable: ${err.message}`\n )\n this._redisAvailable = false\n }\n return false\n }\n }\n\n /**\n * Gets cached health check result from Redis (if available) or in-memory cache.\n * Throws error if Redis is configured but read fails (so caller can return proper error format).\n * @returns {Promise<Object | null>} Cached result or null\n * @throws {Error} If Redis is configured but read fails\n */\n async get() {\n // If Redis is configured, we MUST read from it (don't fall back to memory)\n if (this.redisClient) {\n try {\n let cachedStr\n if (this._redisClientType === REDIS_V3) {\n cachedStr = await new Promise((resolve, reject) => {\n this.redisClient.get(this.cacheKey, (err, result) => {\n if (err) reject(err)\n else resolve(result)\n })\n })\n } else if (\n this._redisClientType === REDIS_V4 ||\n this._redisClientType === IOREDIS\n ) {\n cachedStr = await this.redisClient.get(this.cacheKey)\n }\n\n if (cachedStr) {\n try {\n const cached = JSON.parse(cachedStr)\n if (cached.result && cached.timestamp) {\n const age = Date.now() - cached.timestamp\n if (age < this.cacheTtlMs) {\n // Also update in-memory cache as backup\n this._memoryCache = cached.result\n this._memoryCacheTimestamp = cached.timestamp\n return cached.result\n }\n }\n } catch (parseErr) {\n console.warn(\n `[HealthCheckCache] Failed to parse Redis cache:`,\n parseErr.message\n )\n }\n }\n // No cache in Redis - return null (worker may not have run yet)\n return null\n } catch (redisErr) {\n // Redis read failed - throw error so caller can return proper error format\n this._redisAvailable = false\n throw new Error(`Redis cache read failed: ${redisErr.message}`)\n }\n }\n\n // No Redis configured - fall back to in-memory cache\n if (this._memoryCache && this._memoryCacheTimestamp) {\n const age = Date.now() - this._memoryCacheTimestamp\n if (age < this.cacheTtlMs) {\n return this._memoryCache\n }\n }\n\n return null\n }\n\n /**\n * Sets cached health check result in Redis (if available) and in-memory.\n * @param {Object} result - Health check result to cache\n * @returns {Promise<void>}\n */\n async set(result) {\n const cacheData = {\n result,\n timestamp: Date.now(),\n }\n\n // Update in-memory cache\n this._memoryCache = result\n this._memoryCacheTimestamp = cacheData.timestamp\n\n // Try to update Redis if available\n if (await this._checkRedisAvailable()) {\n try {\n const cacheStr = JSON.stringify(cacheData)\n const ttlSeconds = Math.ceil(this.cacheTtlMs / 1000) + 10\n\n if (this._redisClientType === REDIS_V3) {\n await new Promise((resolve, reject) => {\n this.redisClient.setex(this.cacheKey, ttlSeconds, cacheStr, err => {\n if (err) reject(err)\n else resolve()\n })\n })\n } else if (\n this._redisClientType === REDIS_V4 ||\n this._redisClientType === IOREDIS\n ) {\n await this.redisClient.setex(this.cacheKey, ttlSeconds, cacheStr)\n }\n } catch (redisErr) {\n // Redis write failed, but in-memory cache is updated\n console.warn(\n `[HealthCheckCache] Redis write failed (in-memory cache updated):`,\n redisErr.message\n )\n this._redisAvailable = false\n }\n }\n }\n\n /**\n * Clears the cache (both Redis and in-memory).\n * @returns {Promise<void>}\n */\n async clear() {\n this._memoryCache = null\n this._memoryCacheTimestamp = null\n\n if (await this._checkRedisAvailable()) {\n try {\n if (this._redisClientType === REDIS_V3) {\n await new Promise((resolve, reject) => {\n this.redisClient.del(this.cacheKey, err => {\n if (err) reject(err)\n else resolve()\n })\n })\n } else if (\n this._redisClientType === REDIS_V4 ||\n this._redisClientType === IOREDIS\n ) {\n await this.redisClient.del(this.cacheKey)\n }\n } catch (redisErr) {\n console.warn(`[HealthCheckCache] Redis clear failed:`, redisErr.message)\n }\n }\n }\n\n /**\n * Checks if Redis is configured and available.\n * @returns {boolean}\n */\n isRedisAvailable() {\n return this._redisAvailable && this.redisClient !== null\n }\n}\n\nmodule.exports = { HealthCheckCache }\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"healthCheckCache.js","names":["getRedisClientType","REDIS_V4","IOREDIS","REDIS_V3","require","HealthCheckCache","constructor","options","redisClient","appName","process","env","BUILD_APP_NAME","cacheTtlMs","cacheKey","_memoryCache","_memoryCacheTimestamp","_redisClientType","_redisAvailable","console","warn","_checkRedisAvailable","pong","Promise","resolve","reject","ping","err","result","message","get","cachedStr","cached","JSON","parse","timestamp","age","Date","now","parseErr","redisErr","Error","set","cacheData","cacheStr","stringify","ttlSeconds","Math","ceil","setex","clear","del","isRedisAvailable","module","exports"],"sources":["../../src/health/healthCheckCache.js"],"sourcesContent":["const {\n getRedisClientType,\n REDIS_V4,\n IOREDIS,\n REDIS_V3,\n} = require('../redisUtils')\n\n/**\n * HealthCheckCache provides a shared cache layer for health check results.\n * It uses Redis if available for cross-process sharing, with graceful fallback\n * to in-memory cache if Redis is not configured or unavailable.\n */\nclass HealthCheckCache {\n /**\n * @param {Object} options\n * @param {any} [options.redisClient] - Redis client instance (optional)\n * @param {string} [options.appName] - Application name for cache key\n * @param {number} [options.cacheTtlMs=60000] - Cache TTL in milliseconds\n */\n constructor(options = {}) {\n this.redisClient = options.redisClient || null\n this.appName =\n options.appName || process.env.BUILD_APP_NAME || 'unknown-app'\n this.cacheTtlMs = options.cacheTtlMs ?? 60_000\n this.cacheKey = `healthcheck:${this.appName}`\n\n /** In-memory fallback cache */\n this._memoryCache = null\n this._memoryCacheTimestamp = null\n\n if (this.redisClient) {\n this._redisClientType = getRedisClientType(this.redisClient)\n this._redisAvailable = true\n } else {\n this._redisAvailable = false\n console.warn(\n `[HealthCheckCache] Redis not configured for ${this.appName}, using in-memory cache only (not shared across processes)`\n )\n }\n }\n\n /**\n * Checks if Redis is available and working.\n * @returns {Promise<boolean>}\n * @private\n */\n async _checkRedisAvailable() {\n if (!this.redisClient || !this._redisAvailable) {\n return false\n }\n\n try {\n let pong\n if (this._redisClientType === REDIS_V3) {\n pong = await new Promise((resolve, reject) => {\n this.redisClient.ping((err, result) => {\n if (err) reject(err)\n else resolve(result)\n })\n })\n } else if (\n this._redisClientType === REDIS_V4 ||\n this._redisClientType === IOREDIS\n ) {\n pong = await this.redisClient.ping()\n } else {\n return false\n }\n return pong === 'PONG'\n } catch (err) {\n if (this._redisAvailable) {\n console.warn(\n `[HealthCheckCache] Redis became unavailable: ${err.message}`\n )\n this._redisAvailable = false\n }\n return false\n }\n }\n\n /**\n * Gets cached health check result from Redis (if available) or in-memory cache.\n * Throws error if Redis is configured but read fails (so caller can return proper error format).\n * @returns {Promise<Object | null>} Cached result or null\n * @throws {Error} If Redis is configured but read fails\n */\n async get() {\n if (this.redisClient) {\n try {\n let cachedStr\n if (this._redisClientType === REDIS_V3) {\n cachedStr = await new Promise((resolve, reject) => {\n this.redisClient.get(this.cacheKey, (err, result) => {\n if (err) reject(err)\n else resolve(result)\n })\n })\n } else if (\n this._redisClientType === REDIS_V4 ||\n this._redisClientType === IOREDIS\n ) {\n cachedStr = await this.redisClient.get(this.cacheKey)\n }\n\n if (cachedStr) {\n try {\n const cached = JSON.parse(cachedStr)\n if (cached.result && cached.timestamp) {\n const age = Date.now() - cached.timestamp\n if (age < this.cacheTtlMs) {\n this._memoryCache = cached.result\n this._memoryCacheTimestamp = cached.timestamp\n return cached.result\n }\n }\n } catch (parseErr) {\n console.warn(\n `[HealthCheckCache] Failed to parse Redis cache:`,\n parseErr.message\n )\n }\n }\n return null\n } catch (redisErr) {\n this._redisAvailable = false\n throw new Error(`Redis cache read failed: ${redisErr.message}`)\n }\n }\n\n if (this._memoryCache && this._memoryCacheTimestamp) {\n const age = Date.now() - this._memoryCacheTimestamp\n if (age < this.cacheTtlMs) {\n return this._memoryCache\n }\n }\n\n return null\n }\n\n /**\n * Sets cached health check result in Redis (if available) and in-memory.\n * @param {Object} result - Health check result to cache\n * @returns {Promise<void>}\n */\n async set(result) {\n const cacheData = {\n result,\n timestamp: Date.now(),\n }\n\n this._memoryCache = result\n this._memoryCacheTimestamp = cacheData.timestamp\n\n if (await this._checkRedisAvailable()) {\n try {\n const cacheStr = JSON.stringify(cacheData)\n const ttlSeconds = Math.ceil(this.cacheTtlMs / 1000) + 10\n\n if (this._redisClientType === REDIS_V3) {\n await new Promise((resolve, reject) => {\n this.redisClient.setex(this.cacheKey, ttlSeconds, cacheStr, err => {\n if (err) reject(err)\n else resolve()\n })\n })\n } else if (\n this._redisClientType === REDIS_V4 ||\n this._redisClientType === IOREDIS\n ) {\n await this.redisClient.setex(this.cacheKey, ttlSeconds, cacheStr)\n }\n } catch (redisErr) {\n console.warn(\n `[HealthCheckCache] Redis write failed (in-memory cache updated):`,\n redisErr.message\n )\n this._redisAvailable = false\n }\n }\n }\n\n /**\n * Clears the cache (both Redis and in-memory).\n * @returns {Promise<void>}\n */\n async clear() {\n this._memoryCache = null\n this._memoryCacheTimestamp = null\n\n if (await this._checkRedisAvailable()) {\n try {\n if (this._redisClientType === REDIS_V3) {\n await new Promise((resolve, reject) => {\n this.redisClient.del(this.cacheKey, err => {\n if (err) reject(err)\n else resolve()\n })\n })\n } else if (\n this._redisClientType === REDIS_V4 ||\n this._redisClientType === IOREDIS\n ) {\n await this.redisClient.del(this.cacheKey)\n }\n } catch (redisErr) {\n console.warn(`[HealthCheckCache] Redis clear failed:`, redisErr.message)\n }\n }\n }\n\n /**\n * Checks if Redis is configured and available.\n * @returns {boolean}\n */\n isRedisAvailable() {\n return this._redisAvailable && this.redisClient !== null\n }\n}\n\nmodule.exports = { HealthCheckCache }\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -1,266 +1,140 @@
|
|
|
1
|
-
export type
|
|
2
|
-
export type ComponentHealth = {
|
|
3
|
-
/**
|
|
4
|
-
* - Component health status
|
|
5
|
-
*/
|
|
6
|
-
status: HealthStatus;
|
|
7
|
-
/**
|
|
8
|
-
* - Error message if status is unhealthy
|
|
9
|
-
*/
|
|
10
|
-
error?: string | undefined;
|
|
11
|
-
/**
|
|
12
|
-
* - Optional status message (deprecated, use error)
|
|
13
|
-
*/
|
|
14
|
-
message?: string | undefined;
|
|
15
|
-
/**
|
|
16
|
-
* - Connection latency in milliseconds
|
|
17
|
-
*/
|
|
18
|
-
latencyMs?: number | undefined;
|
|
19
|
-
};
|
|
20
|
-
export type DatabaseClusterHealth = {
|
|
21
|
-
/**
|
|
22
|
-
* - Overall databases status
|
|
23
|
-
*/
|
|
24
|
-
status: HealthStatus;
|
|
25
|
-
/**
|
|
26
|
-
* - Individual cluster health
|
|
27
|
-
*/
|
|
28
|
-
clusters: {
|
|
29
|
-
[x: string]: ComponentHealth;
|
|
30
|
-
};
|
|
31
|
-
};
|
|
32
|
-
export type HealthCheckResult = {
|
|
33
|
-
/**
|
|
34
|
-
* - Overall health status
|
|
35
|
-
*/
|
|
36
|
-
status: HealthStatus;
|
|
37
|
-
/**
|
|
38
|
-
* - ISO timestamp of the check
|
|
39
|
-
*/
|
|
40
|
-
timestamp: string;
|
|
41
|
-
/**
|
|
42
|
-
* - Individual service health checks
|
|
43
|
-
*/
|
|
44
|
-
checks: {
|
|
45
|
-
[x: string]: ComponentHealth | DatabaseClusterHealth;
|
|
46
|
-
};
|
|
47
|
-
/**
|
|
48
|
-
* - Top-level error messages (not related to specific services)
|
|
49
|
-
*/
|
|
50
|
-
errors?: string[] | undefined;
|
|
51
|
-
};
|
|
52
|
-
export type CachedHealthResult = {
|
|
53
|
-
/**
|
|
54
|
-
* - The cached health check result
|
|
55
|
-
*/
|
|
56
|
-
result: HealthCheckResult;
|
|
57
|
-
/**
|
|
58
|
-
* - Unix timestamp when cached
|
|
59
|
-
*/
|
|
60
|
-
timestamp: number;
|
|
61
|
-
};
|
|
62
|
-
export type DatabaseConfig = {
|
|
63
|
-
/**
|
|
64
|
-
* - Database/cluster name
|
|
65
|
-
*/
|
|
1
|
+
export type HealthResource = {
|
|
66
2
|
name: string;
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
3
|
+
url?: string;
|
|
4
|
+
} | {
|
|
5
|
+
name: string;
|
|
6
|
+
client: any;
|
|
71
7
|
};
|
|
72
8
|
/**
|
|
73
|
-
* @typedef {
|
|
74
|
-
*/
|
|
75
|
-
/**
|
|
76
|
-
* @typedef {Object} ComponentHealth
|
|
77
|
-
* @property {HealthStatus} status - Component health status
|
|
78
|
-
* @property {string} [error] - Error message if status is unhealthy
|
|
79
|
-
* @property {string} [message] - Optional status message (deprecated, use error)
|
|
80
|
-
* @property {number} [latencyMs] - Connection latency in milliseconds
|
|
81
|
-
*/
|
|
82
|
-
/**
|
|
83
|
-
* @typedef {Object} DatabaseClusterHealth
|
|
84
|
-
* @property {HealthStatus} status - Overall databases status
|
|
85
|
-
* @property {Object<string, ComponentHealth>} clusters - Individual cluster health
|
|
86
|
-
*/
|
|
87
|
-
/**
|
|
88
|
-
* @typedef {Object} HealthCheckResult
|
|
89
|
-
* @property {HealthStatus} status - Overall health status
|
|
90
|
-
* @property {string} timestamp - ISO timestamp of the check
|
|
91
|
-
* @property {Object<string, ComponentHealth | DatabaseClusterHealth>} checks - Individual service health checks
|
|
92
|
-
* @property {string[]} [errors] - Top-level error messages (not related to specific services)
|
|
93
|
-
*/
|
|
94
|
-
/**
|
|
95
|
-
* @typedef {Object} CachedHealthResult
|
|
96
|
-
* @property {HealthCheckResult} result - The cached health check result
|
|
97
|
-
* @property {number} timestamp - Unix timestamp when cached
|
|
98
|
-
*/
|
|
99
|
-
/**
|
|
100
|
-
* @typedef {Object} DatabaseConfig
|
|
101
|
-
* @property {string} name - Database/cluster name
|
|
102
|
-
* @property {string} url - Connection URL
|
|
103
|
-
*/
|
|
104
|
-
/**
|
|
105
|
-
* HealthCheckClient provides a health check middleware for external monitoring services
|
|
106
|
-
* like BetterStack. It validates database and Redis connections with rate limiting
|
|
107
|
-
* to prevent excessive load on backend services.
|
|
108
|
-
*
|
|
109
|
-
* Features:
|
|
110
|
-
* - Multi-cluster DB validation (PostgreSQL)
|
|
111
|
-
* - Redis connection validation (supports ioredis, node-redis v3/v4)
|
|
112
|
-
* - Result caching (default: 60 seconds) to prevent overloading services
|
|
113
|
-
* - Express middleware support
|
|
114
|
-
* - BetterStack-compatible JSON response format
|
|
9
|
+
* @typedef {{ name: string, url?: string } | { name: string, client: any }} HealthResource
|
|
115
10
|
*/
|
|
116
11
|
export class HealthCheckClient {
|
|
117
12
|
/**
|
|
118
13
|
* @param {Object} options
|
|
119
|
-
* @param {
|
|
120
|
-
* @param {
|
|
121
|
-
* @param {Object
|
|
122
|
-
* @param {
|
|
123
|
-
* @param {boolean} [options.includeRedisCheck=false] - Include Redis health check in results (for backend)
|
|
124
|
-
* @param {number} [options.cacheTtlMs=60000] - Cache TTL in milliseconds (default: 60s)
|
|
125
|
-
* @param {string} [options.appName] - Application name for logging
|
|
14
|
+
* @param {HealthResource[]} options.resources - Must include Redis resource with client
|
|
15
|
+
* @param {number} [options.cacheTtlMs]
|
|
16
|
+
* @param {Object} [options.config]
|
|
17
|
+
* @param {string} [options.appName]
|
|
126
18
|
*/
|
|
127
19
|
constructor(options?: {
|
|
128
|
-
|
|
129
|
-
databaseName?: string | undefined;
|
|
130
|
-
additionalDatabaseUrls?: {
|
|
131
|
-
[x: string]: string;
|
|
132
|
-
} | undefined;
|
|
133
|
-
redisClient?: any;
|
|
134
|
-
includeRedisCheck?: boolean | undefined;
|
|
20
|
+
resources: HealthResource[];
|
|
135
21
|
cacheTtlMs?: number | undefined;
|
|
22
|
+
config?: Object | undefined;
|
|
136
23
|
appName?: string | undefined;
|
|
137
24
|
});
|
|
138
|
-
|
|
139
|
-
|
|
25
|
+
healthConfig: {
|
|
26
|
+
constructor?: Function | undefined;
|
|
27
|
+
toString?: (() => string) | undefined;
|
|
28
|
+
toLocaleString?: (() => string) | undefined;
|
|
29
|
+
valueOf?: (() => Object) | undefined;
|
|
30
|
+
hasOwnProperty?: ((v: PropertyKey) => boolean) | undefined;
|
|
31
|
+
isPrototypeOf?: ((v: Object) => boolean) | undefined;
|
|
32
|
+
propertyIsEnumerable?: ((v: PropertyKey) => boolean) | undefined;
|
|
33
|
+
cacheTtlMs: number;
|
|
34
|
+
checkIntervalMs: number;
|
|
35
|
+
staleThresholdMs: number;
|
|
36
|
+
checkTimeoutMs: number;
|
|
37
|
+
};
|
|
140
38
|
cacheTtlMs: number;
|
|
141
39
|
appName: string;
|
|
142
40
|
prefixLogs: string;
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
41
|
+
_cachedResult: {
|
|
42
|
+
result: {
|
|
43
|
+
status: string;
|
|
44
|
+
lastCheckAt: number;
|
|
45
|
+
resources: {};
|
|
46
|
+
isStale: boolean;
|
|
47
|
+
config: {
|
|
48
|
+
constructor?: Function | undefined;
|
|
49
|
+
toString?: (() => string) | undefined;
|
|
50
|
+
toLocaleString?: (() => string) | undefined;
|
|
51
|
+
valueOf?: (() => Object) | undefined;
|
|
52
|
+
hasOwnProperty?: ((v: PropertyKey) => boolean) | undefined;
|
|
53
|
+
isPrototypeOf?: ((v: Object) => boolean) | undefined;
|
|
54
|
+
propertyIsEnumerable?: ((v: PropertyKey) => boolean) | undefined;
|
|
55
|
+
cacheTtlMs: number;
|
|
56
|
+
checkIntervalMs: number;
|
|
57
|
+
staleThresholdMs: number;
|
|
58
|
+
checkTimeoutMs: number;
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
timestamp: number;
|
|
62
|
+
} | null;
|
|
63
|
+
_refreshPromise: any;
|
|
64
|
+
_databasePools: Map<any, any>;
|
|
65
|
+
/** @type {HealthResource[]} */
|
|
66
|
+
_resources: HealthResource[];
|
|
153
67
|
_redisClientType: string | undefined;
|
|
154
68
|
_cache: HealthCheckCache;
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
* Returns null if no cache is available. This is used by endpoints to read-only access.
|
|
214
|
-
* If Redis fails, returns error result with proper format.
|
|
215
|
-
*
|
|
216
|
-
* @returns {Promise<HealthCheckResult | null>} Cached result, error result if Redis fails, or null if not available
|
|
217
|
-
*/
|
|
218
|
-
getCachedResult(): Promise<HealthCheckResult | null>;
|
|
219
|
-
/**
|
|
220
|
-
* Forces a refresh of the health check cache.
|
|
221
|
-
* This is used by background workers to periodically update the cache.
|
|
222
|
-
* Updates shared cache (Redis if available, otherwise in-memory).
|
|
223
|
-
*
|
|
224
|
-
* @returns {Promise<HealthCheckResult>}
|
|
225
|
-
*/
|
|
226
|
-
refreshCache(): Promise<HealthCheckResult>;
|
|
227
|
-
/**
|
|
228
|
-
* Clears the cached health check result, forcing the next check to be fresh.
|
|
229
|
-
*/
|
|
69
|
+
_getRedisClientForCache(): any;
|
|
70
|
+
_getPool(name: any, url: any): any;
|
|
71
|
+
_isCacheValid(): boolean;
|
|
72
|
+
_checkDatabase(resource: any): Promise<{
|
|
73
|
+
status: string;
|
|
74
|
+
error: string;
|
|
75
|
+
} | {
|
|
76
|
+
status: string;
|
|
77
|
+
error?: undefined;
|
|
78
|
+
}>;
|
|
79
|
+
_checkRedis(resource: any): Promise<{
|
|
80
|
+
status: string;
|
|
81
|
+
error?: undefined;
|
|
82
|
+
} | {
|
|
83
|
+
status: string;
|
|
84
|
+
error: string;
|
|
85
|
+
}>;
|
|
86
|
+
_performHealthCheckInternal(): Promise<{
|
|
87
|
+
status: string;
|
|
88
|
+
lastCheckAt: number;
|
|
89
|
+
resources: {};
|
|
90
|
+
isStale: boolean;
|
|
91
|
+
config: {
|
|
92
|
+
constructor?: Function | undefined;
|
|
93
|
+
toString?: (() => string) | undefined;
|
|
94
|
+
toLocaleString?: (() => string) | undefined;
|
|
95
|
+
valueOf?: (() => Object) | undefined;
|
|
96
|
+
hasOwnProperty?: ((v: PropertyKey) => boolean) | undefined;
|
|
97
|
+
isPrototypeOf?: ((v: Object) => boolean) | undefined;
|
|
98
|
+
propertyIsEnumerable?: ((v: PropertyKey) => boolean) | undefined;
|
|
99
|
+
cacheTtlMs: number;
|
|
100
|
+
checkIntervalMs: number;
|
|
101
|
+
staleThresholdMs: number;
|
|
102
|
+
checkTimeoutMs: number;
|
|
103
|
+
};
|
|
104
|
+
}>;
|
|
105
|
+
_formatResult(result: any, cached?: boolean): any;
|
|
106
|
+
performHealthCheck(): Promise<any>;
|
|
107
|
+
getCachedResult(): Promise<any>;
|
|
108
|
+
refreshCache(): Promise<{
|
|
109
|
+
status: string;
|
|
110
|
+
lastCheckAt: number;
|
|
111
|
+
resources: {};
|
|
112
|
+
isStale: boolean;
|
|
113
|
+
config: {
|
|
114
|
+
constructor?: Function | undefined;
|
|
115
|
+
toString?: (() => string) | undefined;
|
|
116
|
+
toLocaleString?: (() => string) | undefined;
|
|
117
|
+
valueOf?: (() => Object) | undefined;
|
|
118
|
+
hasOwnProperty?: ((v: PropertyKey) => boolean) | undefined;
|
|
119
|
+
isPrototypeOf?: ((v: Object) => boolean) | undefined;
|
|
120
|
+
propertyIsEnumerable?: ((v: PropertyKey) => boolean) | undefined;
|
|
121
|
+
cacheTtlMs: number;
|
|
122
|
+
checkIntervalMs: number;
|
|
123
|
+
staleThresholdMs: number;
|
|
124
|
+
checkTimeoutMs: number;
|
|
125
|
+
};
|
|
126
|
+
}>;
|
|
230
127
|
clearCache(): void;
|
|
231
|
-
/**
|
|
232
|
-
* Builds a list of error messages from health check result.
|
|
233
|
-
* All error messages are sanitized to remove sensitive information.
|
|
234
|
-
* @param {HealthCheckResult} result - Health check result
|
|
235
|
-
* @returns {string[]} Array of sanitized error messages
|
|
236
|
-
* @private
|
|
237
|
-
*/
|
|
238
|
-
private _getErrorMessages;
|
|
239
|
-
/**
|
|
240
|
-
* Express middleware handler for health check endpoint.
|
|
241
|
-
* Returns 200 for healthy/degraded, 503 for unhealthy.
|
|
242
|
-
* Response includes errors array when status is not healthy.
|
|
243
|
-
* All sensitive data (passwords, connection strings, etc.) is masked.
|
|
244
|
-
*
|
|
245
|
-
* This handler only reads from cache and never triggers database queries.
|
|
246
|
-
* Use a background worker to periodically refresh the cache.
|
|
247
|
-
*
|
|
248
|
-
* @returns {(req: any, res: any) => Promise<void>} Express request handler
|
|
249
|
-
*/
|
|
250
128
|
healthHandler(): (req: any, res: any) => Promise<void>;
|
|
251
|
-
|
|
252
|
-
* Register health check endpoint on an Express app.
|
|
253
|
-
*
|
|
254
|
-
* @param {import('express').Application} app - Express application
|
|
255
|
-
* @param {string} [path='/health'] - Path for the health endpoint
|
|
256
|
-
*/
|
|
257
|
-
registerHealthEndpoint(app: any, path?: string | undefined): void;
|
|
258
|
-
/**
|
|
259
|
-
* Cleanup resources (database pools).
|
|
260
|
-
* @returns {Promise<void>}
|
|
261
|
-
*/
|
|
129
|
+
registerHealthEndpoint(app: any, path?: string): void;
|
|
262
130
|
cleanup(): Promise<void>;
|
|
263
131
|
}
|
|
264
|
-
|
|
132
|
+
/** @type {{ cacheTtlMs: number, checkIntervalMs: number, staleThresholdMs: number, checkTimeoutMs: number }} */
|
|
133
|
+
export const DEFAULT_HEALTH_CONFIG: {
|
|
134
|
+
cacheTtlMs: number;
|
|
135
|
+
checkIntervalMs: number;
|
|
136
|
+
staleThresholdMs: number;
|
|
137
|
+
checkTimeoutMs: number;
|
|
138
|
+
};
|
|
265
139
|
import { HealthCheckCache } from "./healthCheckCache";
|
|
266
140
|
//# sourceMappingURL=healthCheckClient.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"healthCheckClient.d.ts","sourceRoot":"","sources":["../../src/health/healthCheckClient.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"healthCheckClient.d.ts","sourceRoot":"","sources":["../../src/health/healthCheckClient.js"],"names":[],"mappings":"6BA6Da;IAAE,MAAM,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,MAAM,MAAM,CAAC;IAAC,MAAM,EAAE,GAAG,CAAA;CAAE;AAD3E;;GAEG;AACH;IACE;;;;;;OAMG;IACH;QALqC,SAAS,EAAnC,cAAc,EAAE;QACC,UAAU;QACV,MAAM;QACN,OAAO;OA8BlC;IA3BC;;;;;;;;;;;;MAAmE;IAInE,mBAA8C;IAC9C,gBACgE;IAEhE,mBAAmD;IAEnD;;;;;;;;;;;;;;;;;;;;;aAAyB;IACzB,qBAA2B;IAC3B,8BAA+B;IAE/B,+BAA+B;IAC/B,YADW,cAAc,EAAE,CACc;IAIvC,qCAAuD;IAGzD,yBAIE;IAGJ,+BAGC;IAED,mCAaC;IAED,yBAGC;IAED;;;;;;OAiBC;IAED;;;;;;OA0BC;IAED;;;;;;;;;;;;;;;;;;OAiCC;IAED,kDAWC;IAED,mCA2BC;IAED,gCAkBC;IAED;;;;;;;;;;;;;;;;;;OAIC;IAED,mBAGC;IAED,uDA0CC;IAED,sDAGC;IAED,yBASC;CACF;AA3UD,gHAAgH;AAChH,oCADW;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAC;IAAC,gBAAgB,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,CAM3G"}
|