@adalo/metrics 0.1.160 → 0.1.161
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/metrics/metricsQueueRedisClient.d.ts +0 -29
- package/lib/metrics/metricsQueueRedisClient.d.ts.map +1 -1
- package/lib/metrics/metricsQueueRedisClient.js +2 -1
- package/lib/metrics/metricsQueueRedisClient.js.map +1 -1
- package/package.json +1 -1
- package/src/metrics/metricsQueueRedisClient.js +2 -1
|
@@ -5,35 +5,6 @@
|
|
|
5
5
|
* @extends RedisMetricsClient
|
|
6
6
|
*/
|
|
7
7
|
export class QueueRedisMetricsClient extends RedisMetricsClient {
|
|
8
|
-
/**
|
|
9
|
-
* @param {Object} options
|
|
10
|
-
* @param {any} options.redisClient - Redis client instance (required)
|
|
11
|
-
* @param {string} [options.appName] - Application name (from BaseMetricsClient)
|
|
12
|
-
* @param {string} [options.dynoId] - Dyno/instance ID (from BaseMetricsClient)
|
|
13
|
-
* @param {string} [options.processType] - Process type (from BaseMetricsClient)
|
|
14
|
-
* @param {boolean} [options.enabled] - Enable metrics collection (from BaseMetricsClient)
|
|
15
|
-
* @param {boolean} [options.logValues] - Log metrics values (from BaseMetricsClient)
|
|
16
|
-
* @param {string} [options.pushgatewayUrl] - PushGateway URL (from BaseMetricsClient)
|
|
17
|
-
* @param {string} [options.pushgatewaySecret] - PushGateway secret token (from BaseMetricsClient)
|
|
18
|
-
* @param {number} [options.intervalSec] - Interval in seconds for pushing metrics (from BaseMetricsClient)
|
|
19
|
-
* @param {boolean} [options.removeOldMetrics] - Remove old metrics by service (from BaseMetricsClient)
|
|
20
|
-
* @param {function} [options.startupValidation] - Function to validate startup (from BaseMetricsClient)
|
|
21
|
-
* @param {boolean} [options.disablePushgateway] - Disable pushing to Pushgateway (use HTTP scraping instead)
|
|
22
|
-
*/
|
|
23
|
-
constructor({ redisClient, metricsConfig }?: {
|
|
24
|
-
redisClient: any;
|
|
25
|
-
appName?: string | undefined;
|
|
26
|
-
dynoId?: string | undefined;
|
|
27
|
-
processType?: string | undefined;
|
|
28
|
-
enabled?: boolean | undefined;
|
|
29
|
-
logValues?: boolean | undefined;
|
|
30
|
-
pushgatewayUrl?: string | undefined;
|
|
31
|
-
pushgatewaySecret?: string | undefined;
|
|
32
|
-
intervalSec?: number | undefined;
|
|
33
|
-
removeOldMetrics?: boolean | undefined;
|
|
34
|
-
startupValidation?: Function | undefined;
|
|
35
|
-
disablePushgateway?: boolean | undefined;
|
|
36
|
-
});
|
|
37
8
|
getConfiguredQueueNames: () => string[];
|
|
38
9
|
startupValidation: () => boolean;
|
|
39
10
|
/** Cache for queue objects to avoid multiple connections */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metricsQueueRedisClient.d.ts","sourceRoot":"","sources":["../../src/metrics/metricsQueueRedisClient.js"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH;
|
|
1
|
+
{"version":3,"file":"metricsQueueRedisClient.d.ts","sourceRoot":"","sources":["../../src/metrics/metricsQueueRedisClient.js"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH;IAiEI,wCAAsD;IACtD,iCAA0C;IAE1C,4DAA4D;IAa5D,0BAA2B;IAE3B,qCAAqC;IACrC,oDAIE;IAKJ;;;;;OAKG;IACH,cAHW,MAAM,EAAE,KACN,QAAQ,GAAG,CAAC,CA6BxB;IAED,8BAGC;IAED,2DA6BC;IAED;;;;;;OAmBC;IAED;;;;;;OAwBC;IAED;;;;;;;;;;;OAWG;IACH,uCAHW,MAAM,KACJ,QAAQ,IAAI,CAAC,CAyCzB;IAED;;;OAGG;IACH,2BAFa,QAAQ,IAAI,CAAC,CAuCzB;CAqCF"}
|
|
@@ -19,6 +19,7 @@ class QueueRedisMetricsClient extends RedisMetricsClient {
|
|
|
19
19
|
/**
|
|
20
20
|
* @param {Object} options
|
|
21
21
|
* @param {any} options.redisClient - Redis client instance (required)
|
|
22
|
+
* @param {boolean} [options.gracefulShutdownRedis] - Passed to RedisMetricsClient
|
|
22
23
|
* @param {string} [options.appName] - Application name (from BaseMetricsClient)
|
|
23
24
|
* @param {string} [options.dynoId] - Dyno/instance ID (from BaseMetricsClient)
|
|
24
25
|
* @param {string} [options.processType] - Process type (from BaseMetricsClient)
|
|
@@ -33,7 +34,7 @@ class QueueRedisMetricsClient extends RedisMetricsClient {
|
|
|
33
34
|
*/
|
|
34
35
|
constructor({
|
|
35
36
|
redisClient,
|
|
36
|
-
metricsConfig
|
|
37
|
+
...metricsConfig
|
|
37
38
|
} = {}) {
|
|
38
39
|
const getConfiguredQueueNames = () => {
|
|
39
40
|
if (!process.env.METRICS_APP_REDIS_BQ) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metricsQueueRedisClient.js","names":["RedisMetricsClient","require","IOREDIS","REDIS_V3","REDIS_V4","QueueRedisMetricsClient","constructor","redisClient","metricsConfig","getConfiguredQueueNames","process","env","METRICS_APP_REDIS_BQ","Error","allQueues","split","map","q","trim","filter","Boolean","length","Set","startupValidation","queueNames","console","info","error","message","queueCache","Map","queueJobsGauge","createGauge","name","help","labelNames","withDefaultLabels","_setCleanupHandlers","_send","args","Promise","reject","redisClientType","resolve","send_command","slice","err","result","sendCommand","call","_toNumber","v","n","parseInt","String","Number","isFinite","_getQueueType","queueName","forced","METRICS_QUEUE_TYPE","toLowerCase","bullPrefix","BULL_QUEUE_PREFIX","beePrefix","BEE_QUEUE_PREFIX","METRICS_BEE_QUEUE_PREFIX","bullWaitKey","beeWaitKey","bullExists","beeExists","all","_getBullHealth","prefix","base","waiting","active","succeeded","failed","delayed","_getBeeQueueHealth","collectSingleQueueMetrics","queueType","health","labels","getDefaultLabels","queue_name","set","status","warn","collectQueueMetrics","collectRedisMetrics","allSettled","gatewayPush","clearAllCounters","metricsLogValues","metricObjects","registry","getMetricsAsJSON","JSON","stringify","includes","startPush","intervalSec","_startPush","catch","on","cleanup","queue","close","module","exports"],"sources":["../../src/metrics/metricsQueueRedisClient.js"],"sourcesContent":["const { RedisMetricsClient } = require('./metricsRedisClient')\nconst { IOREDIS, REDIS_V3, REDIS_V4 } = require('../redisUtils')\n\n/**\n * QueueRedisMetricsClient extends RedisMetricsClient to collect\n * Redis and Bee Queue metrics periodically and push them to Prometheus Pushgateway.\n *\n * @extends RedisMetricsClient\n */\nclass QueueRedisMetricsClient extends RedisMetricsClient {\n /**\n * @param {Object} options\n * @param {any} options.redisClient - Redis client instance (required)\n * @param {string} [options.appName] - Application name (from BaseMetricsClient)\n * @param {string} [options.dynoId] - Dyno/instance ID (from BaseMetricsClient)\n * @param {string} [options.processType] - Process type (from BaseMetricsClient)\n * @param {boolean} [options.enabled] - Enable metrics collection (from BaseMetricsClient)\n * @param {boolean} [options.logValues] - Log metrics values (from BaseMetricsClient)\n * @param {string} [options.pushgatewayUrl] - PushGateway URL (from BaseMetricsClient)\n * @param {string} [options.pushgatewaySecret] - PushGateway secret token (from BaseMetricsClient)\n * @param {number} [options.intervalSec] - Interval in seconds for pushing metrics (from BaseMetricsClient)\n * @param {boolean} [options.removeOldMetrics] - Remove old metrics by service (from BaseMetricsClient)\n * @param {function} [options.startupValidation] - Function to validate startup (from BaseMetricsClient)\n * @param {boolean} [options.disablePushgateway] - Disable pushing to Pushgateway (use HTTP scraping instead)\n */\n constructor({ redisClient, metricsConfig = {} } = {}) {\n const getConfiguredQueueNames = () => {\n if (!process.env.METRICS_APP_REDIS_BQ) {\n throw new Error(\n 'No queues configured for monitoring. Set METRICS_APP_REDIS_BQ with comma-separated queue names'\n )\n }\n\n const allQueues = process.env.METRICS_APP_REDIS_BQ.split(',')\n .map(q => q.trim())\n .filter(Boolean)\n\n if (allQueues.length === 0) {\n throw new Error(\n 'METRICS_APP_REDIS_BQ is empty or contains only whitespace. ' +\n 'Example: METRICS_APP_REDIS_BQ=\"adalo-compile,adalo-migrations\"'\n )\n }\n\n return [...new Set(allQueues)]\n }\n\n const startupValidation = () => {\n try {\n const queueNames = getConfiguredQueueNames()\n console.info(\n `[queue-metrics] Queue & Redis metrics collection starting for ${queueNames.length} queues`\n )\n return true\n } catch (error) {\n console.error(`[queue-metrics] ❌ Cannot start: ${error.message}`)\n console.error(\n `[queue-metrics] 💡 Example: METRICS_APP_REDIS_BQ=\"adalo-compile,adalo-migrations\"`\n )\n console.error(\n `[queue-metrics] 💡 Optional: METRICS_QUEUE_INTERVAL_SEC=\"10\"`\n )\n console.error(`[queue-metrics] Skipping queue metrics collection`)\n return false\n }\n }\n\n super({\n ...metricsConfig,\n redisClient,\n startupValidation,\n })\n\n this.getConfiguredQueueNames = getConfiguredQueueNames\n this.startupValidation = startupValidation\n\n /** Cache for queue objects to avoid multiple connections */\n // NOTE:\n // Historically we used `bee-queue`'s `Queue#checkHealth()` here.\n // But bee-queue depends on `redis@3`, which is not compatible with Node 22\n // in some environments and can crash with errors like:\n // - \"this._ready.then is not a function\"\n // - \"TypeError: this.stream.once is not a function\"\n //\n // To avoid pulling in node-redis v3 at runtime, we read queue counters\n // directly from Redis using the *provided* redis client (ioredis or node-redis).\n //\n // Keep this map reserved for possible future caching (e.g. key schema detection),\n // but we no longer store Queue instances.\n this.queueCache = new Map()\n\n /** Gauge for queue jobs by status */\n this.queueJobsGauge = this.createGauge({\n name: 'app_queue_jobs_count',\n help: 'Number of app jobs in the queue by status',\n labelNames: this.withDefaultLabels(['queue_name', 'status']),\n })\n\n this._setCleanupHandlers()\n }\n\n /**\n * Execute a Redis command in a client-type safe way.\n *\n * @param {string[]} args Command args array, e.g. ['LLEN', 'key']\n * @returns {Promise<any>}\n */\n _send = args => {\n if (!this.redisClient) {\n return Promise.reject(new Error('Redis client not provided'))\n }\n\n // node-redis v3 (callback API)\n if (this.redisClientType === REDIS_V3) {\n return new Promise((resolve, reject) => {\n this.redisClient.send_command(args[0], args.slice(1), (err, result) => {\n if (err) reject(err)\n else resolve(result)\n })\n })\n }\n\n // node-redis v4 (Promise API)\n if (this.redisClientType === REDIS_V4) {\n return this.redisClient.sendCommand(args)\n }\n\n // ioredis (Promise API)\n if (this.redisClientType === IOREDIS) {\n // ioredis supports `.call(command, ...args)`\n return this.redisClient.call(args[0], ...args.slice(1))\n }\n\n return Promise.reject(new Error('Unsupported Redis client type'))\n }\n\n _toNumber = v => {\n const n = typeof v === 'number' ? v : parseInt(String(v || '0'), 10)\n return Number.isFinite(n) ? n : 0\n }\n\n _getQueueType = async queueName => {\n const forced = (process.env.METRICS_QUEUE_TYPE || '').trim().toLowerCase()\n if (forced === 'bull' || forced === 'bee') return forced\n\n const bullPrefix =\n (process.env.BULL_QUEUE_PREFIX || 'bull').trim() || 'bull'\n const beePrefix =\n (\n process.env.BEE_QUEUE_PREFIX ||\n process.env.METRICS_BEE_QUEUE_PREFIX ||\n 'bq'\n ).trim() || 'bq'\n\n // Detect by checking the canonical \"waiting\" key names.\n const bullWaitKey = `${bullPrefix}:${queueName}:wait`\n const beeWaitKey = `${beePrefix}:${queueName}:waiting`\n\n try {\n const [bullExists, beeExists] = await Promise.all([\n this._send(['EXISTS', bullWaitKey]),\n this._send(['EXISTS', beeWaitKey]),\n ])\n if (this._toNumber(bullExists) > 0) return 'bull'\n if (this._toNumber(beeExists) > 0) return 'bee'\n } catch {\n // If EXISTS is blocked/unavailable, fall back to trying bull first.\n }\n\n return 'bull'\n }\n\n _getBullHealth = async queueName => {\n const prefix = (process.env.BULL_QUEUE_PREFIX || 'bull').trim() || 'bull'\n const base = `${prefix}:${queueName}:`\n\n const [waiting, active, succeeded, failed, delayed] = await Promise.all([\n this._send(['LLEN', `${base}wait`]),\n this._send(['LLEN', `${base}active`]),\n this._send(['ZCARD', `${base}completed`]),\n this._send(['ZCARD', `${base}failed`]),\n this._send(['ZCARD', `${base}delayed`]),\n ])\n\n return {\n waiting: this._toNumber(waiting),\n active: this._toNumber(active),\n succeeded: this._toNumber(succeeded),\n failed: this._toNumber(failed),\n delayed: this._toNumber(delayed),\n }\n }\n\n _getBeeQueueHealth = async queueName => {\n const prefix =\n (\n process.env.BEE_QUEUE_PREFIX ||\n process.env.METRICS_BEE_QUEUE_PREFIX ||\n 'bq'\n ).trim() || 'bq'\n const base = `${prefix}:${queueName}:`\n\n const [waiting, active, succeeded, failed, delayed] = await Promise.all([\n this._send(['LLEN', `${base}waiting`]),\n this._send(['LLEN', `${base}active`]),\n this._send(['SCARD', `${base}succeeded`]),\n this._send(['SCARD', `${base}failed`]),\n this._send(['ZCARD', `${base}delayed`]),\n ])\n\n return {\n waiting: this._toNumber(waiting),\n active: this._toNumber(active),\n succeeded: this._toNumber(succeeded),\n failed: this._toNumber(failed),\n delayed: this._toNumber(delayed),\n }\n }\n\n /**\n * Collect metrics for a single queue and set gauges.\n *\n * Supports:\n * - Bull (default): keys like `bull:<queue>:wait`, `...:active`, `...:completed`, `...:failed`, `...:delayed`\n * - Bee-Queue: keys like `bq:<queue>:waiting`, `...:active`, `...:succeeded`, `...:failed`, `...:delayed`\n *\n * Auto-detects queue type unless `METRICS_QUEUE_TYPE` is set to `bull` or `bee`.\n *\n * @param {string} queueName - Name of the queue\n * @returns {Promise<void>}\n */\n collectSingleQueueMetrics = async queueName => {\n try {\n const queueType = await this._getQueueType(queueName)\n const health =\n queueType === 'bee'\n ? await this._getBeeQueueHealth(queueName)\n : await this._getBullHealth(queueName)\n\n const labels = {\n ...this.getDefaultLabels(),\n queue_name: queueName,\n }\n\n this.queueJobsGauge.set(\n { ...labels, status: 'waiting' },\n health.waiting || 0\n )\n this.queueJobsGauge.set(\n { ...labels, status: 'active' },\n health.active || 0\n )\n this.queueJobsGauge.set(\n { ...labels, status: 'succeeded' },\n health.succeeded || 0\n )\n this.queueJobsGauge.set(\n { ...labels, status: 'failed' },\n health.failed || 0\n )\n this.queueJobsGauge.set(\n { ...labels, status: 'delayed' },\n health.delayed || 0\n )\n } catch (error) {\n console.warn(\n `[queue-metrics] Failed to collect metrics for queue ${queueName}:`,\n error.message\n )\n }\n }\n\n /**\n * Collect metrics for all queues and Redis, then push to Pushgateway\n * @returns {Promise<void>}\n */\n collectQueueMetrics = async () => {\n try {\n const queueNames = this.getConfiguredQueueNames()\n\n await this.collectRedisMetrics()\n await Promise.allSettled(\n queueNames.map(queueName => this.collectSingleQueueMetrics(queueName))\n )\n\n await this.gatewayPush()\n this.clearAllCounters()\n\n if (this.metricsLogValues) {\n const metricObjects = await this.registry.getMetricsAsJSON()\n console.info(\n `[queue-metrics] Collected metrics for ${queueNames.length} queues:`,\n JSON.stringify(metricObjects, null, 2)\n )\n }\n } catch (error) {\n if (\n error.message?.includes('No queues configured') ||\n error.message?.includes('METRICS_APP_REDIS_BQ')\n ) {\n console.error(\n `[queue-metrics] ❌ Configuration error: ${error.message}`\n )\n console.error(\n `[queue-metrics] 💡 Example config: METRICS_APP_REDIS_BQ=\"adalo-compile,adalo-migrations\"`\n )\n } else {\n console.error(\n `[queue-metrics] Failed to collect queue metrics: ${error.message}`\n )\n }\n throw error\n }\n }\n\n /**\n * Start periodic collection.\n * @param {number} [intervalSec=this.intervalSec] - Interval in seconds\n */\n startPush = (intervalSec = this.intervalSec) => {\n this._startPush(intervalSec, () => {\n this.collectQueueMetrics().catch(err => {\n console.error(\n `[queue-metrics] Failed to collect queue & Redis metrics:`,\n err\n )\n })\n })\n }\n\n _setCleanupHandlers = () => {\n process.on('SIGINT', this.cleanup)\n process.on('SIGTERM', this.cleanup)\n }\n\n /**\n * Cleanup queues and exit process.\n * Closes queues then runs Redis metrics cleanup (stop push, delete from VM, close Redis).\n * @returns {Promise<void>}\n */\n cleanup = async () => {\n for (const [queueName, queue] of this.queueCache) {\n try {\n await queue.close()\n } catch (err) {\n console.error(`[queue-metrics] Error closing queue ${queueName}:`, err)\n }\n }\n await super.cleanup()\n }\n}\n\nmodule.exports = { QueueRedisMetricsClient }\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"metricsQueueRedisClient.js","names":["RedisMetricsClient","require","IOREDIS","REDIS_V3","REDIS_V4","QueueRedisMetricsClient","constructor","redisClient","metricsConfig","getConfiguredQueueNames","process","env","METRICS_APP_REDIS_BQ","Error","allQueues","split","map","q","trim","filter","Boolean","length","Set","startupValidation","queueNames","console","info","error","message","queueCache","Map","queueJobsGauge","createGauge","name","help","labelNames","withDefaultLabels","_setCleanupHandlers","_send","args","Promise","reject","redisClientType","resolve","send_command","slice","err","result","sendCommand","call","_toNumber","v","n","parseInt","String","Number","isFinite","_getQueueType","queueName","forced","METRICS_QUEUE_TYPE","toLowerCase","bullPrefix","BULL_QUEUE_PREFIX","beePrefix","BEE_QUEUE_PREFIX","METRICS_BEE_QUEUE_PREFIX","bullWaitKey","beeWaitKey","bullExists","beeExists","all","_getBullHealth","prefix","base","waiting","active","succeeded","failed","delayed","_getBeeQueueHealth","collectSingleQueueMetrics","queueType","health","labels","getDefaultLabels","queue_name","set","status","warn","collectQueueMetrics","collectRedisMetrics","allSettled","gatewayPush","clearAllCounters","metricsLogValues","metricObjects","registry","getMetricsAsJSON","JSON","stringify","includes","startPush","intervalSec","_startPush","catch","on","cleanup","queue","close","module","exports"],"sources":["../../src/metrics/metricsQueueRedisClient.js"],"sourcesContent":["const { RedisMetricsClient } = require('./metricsRedisClient')\nconst { IOREDIS, REDIS_V3, REDIS_V4 } = require('../redisUtils')\n\n/**\n * QueueRedisMetricsClient extends RedisMetricsClient to collect\n * Redis and Bee Queue metrics periodically and push them to Prometheus Pushgateway.\n *\n * @extends RedisMetricsClient\n */\nclass QueueRedisMetricsClient extends RedisMetricsClient {\n /**\n * @param {Object} options\n * @param {any} options.redisClient - Redis client instance (required)\n * @param {boolean} [options.gracefulShutdownRedis] - Passed to RedisMetricsClient\n * @param {string} [options.appName] - Application name (from BaseMetricsClient)\n * @param {string} [options.dynoId] - Dyno/instance ID (from BaseMetricsClient)\n * @param {string} [options.processType] - Process type (from BaseMetricsClient)\n * @param {boolean} [options.enabled] - Enable metrics collection (from BaseMetricsClient)\n * @param {boolean} [options.logValues] - Log metrics values (from BaseMetricsClient)\n * @param {string} [options.pushgatewayUrl] - PushGateway URL (from BaseMetricsClient)\n * @param {string} [options.pushgatewaySecret] - PushGateway secret token (from BaseMetricsClient)\n * @param {number} [options.intervalSec] - Interval in seconds for pushing metrics (from BaseMetricsClient)\n * @param {boolean} [options.removeOldMetrics] - Remove old metrics by service (from BaseMetricsClient)\n * @param {function} [options.startupValidation] - Function to validate startup (from BaseMetricsClient)\n * @param {boolean} [options.disablePushgateway] - Disable pushing to Pushgateway (use HTTP scraping instead)\n */\n constructor({ redisClient, ...metricsConfig } = {}) {\n const getConfiguredQueueNames = () => {\n if (!process.env.METRICS_APP_REDIS_BQ) {\n throw new Error(\n 'No queues configured for monitoring. Set METRICS_APP_REDIS_BQ with comma-separated queue names'\n )\n }\n\n const allQueues = process.env.METRICS_APP_REDIS_BQ.split(',')\n .map(q => q.trim())\n .filter(Boolean)\n\n if (allQueues.length === 0) {\n throw new Error(\n 'METRICS_APP_REDIS_BQ is empty or contains only whitespace. ' +\n 'Example: METRICS_APP_REDIS_BQ=\"adalo-compile,adalo-migrations\"'\n )\n }\n\n return [...new Set(allQueues)]\n }\n\n const startupValidation = () => {\n try {\n const queueNames = getConfiguredQueueNames()\n console.info(\n `[queue-metrics] Queue & Redis metrics collection starting for ${queueNames.length} queues`\n )\n return true\n } catch (error) {\n console.error(`[queue-metrics] ❌ Cannot start: ${error.message}`)\n console.error(\n `[queue-metrics] 💡 Example: METRICS_APP_REDIS_BQ=\"adalo-compile,adalo-migrations\"`\n )\n console.error(\n `[queue-metrics] 💡 Optional: METRICS_QUEUE_INTERVAL_SEC=\"10\"`\n )\n console.error(`[queue-metrics] Skipping queue metrics collection`)\n return false\n }\n }\n\n super({\n ...metricsConfig,\n redisClient,\n startupValidation,\n })\n\n this.getConfiguredQueueNames = getConfiguredQueueNames\n this.startupValidation = startupValidation\n\n /** Cache for queue objects to avoid multiple connections */\n // NOTE:\n // Historically we used `bee-queue`'s `Queue#checkHealth()` here.\n // But bee-queue depends on `redis@3`, which is not compatible with Node 22\n // in some environments and can crash with errors like:\n // - \"this._ready.then is not a function\"\n // - \"TypeError: this.stream.once is not a function\"\n //\n // To avoid pulling in node-redis v3 at runtime, we read queue counters\n // directly from Redis using the *provided* redis client (ioredis or node-redis).\n //\n // Keep this map reserved for possible future caching (e.g. key schema detection),\n // but we no longer store Queue instances.\n this.queueCache = new Map()\n\n /** Gauge for queue jobs by status */\n this.queueJobsGauge = this.createGauge({\n name: 'app_queue_jobs_count',\n help: 'Number of app jobs in the queue by status',\n labelNames: this.withDefaultLabels(['queue_name', 'status']),\n })\n\n this._setCleanupHandlers()\n }\n\n /**\n * Execute a Redis command in a client-type safe way.\n *\n * @param {string[]} args Command args array, e.g. ['LLEN', 'key']\n * @returns {Promise<any>}\n */\n _send = args => {\n if (!this.redisClient) {\n return Promise.reject(new Error('Redis client not provided'))\n }\n\n // node-redis v3 (callback API)\n if (this.redisClientType === REDIS_V3) {\n return new Promise((resolve, reject) => {\n this.redisClient.send_command(args[0], args.slice(1), (err, result) => {\n if (err) reject(err)\n else resolve(result)\n })\n })\n }\n\n // node-redis v4 (Promise API)\n if (this.redisClientType === REDIS_V4) {\n return this.redisClient.sendCommand(args)\n }\n\n // ioredis (Promise API)\n if (this.redisClientType === IOREDIS) {\n // ioredis supports `.call(command, ...args)`\n return this.redisClient.call(args[0], ...args.slice(1))\n }\n\n return Promise.reject(new Error('Unsupported Redis client type'))\n }\n\n _toNumber = v => {\n const n = typeof v === 'number' ? v : parseInt(String(v || '0'), 10)\n return Number.isFinite(n) ? n : 0\n }\n\n _getQueueType = async queueName => {\n const forced = (process.env.METRICS_QUEUE_TYPE || '').trim().toLowerCase()\n if (forced === 'bull' || forced === 'bee') return forced\n\n const bullPrefix =\n (process.env.BULL_QUEUE_PREFIX || 'bull').trim() || 'bull'\n const beePrefix =\n (\n process.env.BEE_QUEUE_PREFIX ||\n process.env.METRICS_BEE_QUEUE_PREFIX ||\n 'bq'\n ).trim() || 'bq'\n\n // Detect by checking the canonical \"waiting\" key names.\n const bullWaitKey = `${bullPrefix}:${queueName}:wait`\n const beeWaitKey = `${beePrefix}:${queueName}:waiting`\n\n try {\n const [bullExists, beeExists] = await Promise.all([\n this._send(['EXISTS', bullWaitKey]),\n this._send(['EXISTS', beeWaitKey]),\n ])\n if (this._toNumber(bullExists) > 0) return 'bull'\n if (this._toNumber(beeExists) > 0) return 'bee'\n } catch {\n // If EXISTS is blocked/unavailable, fall back to trying bull first.\n }\n\n return 'bull'\n }\n\n _getBullHealth = async queueName => {\n const prefix = (process.env.BULL_QUEUE_PREFIX || 'bull').trim() || 'bull'\n const base = `${prefix}:${queueName}:`\n\n const [waiting, active, succeeded, failed, delayed] = await Promise.all([\n this._send(['LLEN', `${base}wait`]),\n this._send(['LLEN', `${base}active`]),\n this._send(['ZCARD', `${base}completed`]),\n this._send(['ZCARD', `${base}failed`]),\n this._send(['ZCARD', `${base}delayed`]),\n ])\n\n return {\n waiting: this._toNumber(waiting),\n active: this._toNumber(active),\n succeeded: this._toNumber(succeeded),\n failed: this._toNumber(failed),\n delayed: this._toNumber(delayed),\n }\n }\n\n _getBeeQueueHealth = async queueName => {\n const prefix =\n (\n process.env.BEE_QUEUE_PREFIX ||\n process.env.METRICS_BEE_QUEUE_PREFIX ||\n 'bq'\n ).trim() || 'bq'\n const base = `${prefix}:${queueName}:`\n\n const [waiting, active, succeeded, failed, delayed] = await Promise.all([\n this._send(['LLEN', `${base}waiting`]),\n this._send(['LLEN', `${base}active`]),\n this._send(['SCARD', `${base}succeeded`]),\n this._send(['SCARD', `${base}failed`]),\n this._send(['ZCARD', `${base}delayed`]),\n ])\n\n return {\n waiting: this._toNumber(waiting),\n active: this._toNumber(active),\n succeeded: this._toNumber(succeeded),\n failed: this._toNumber(failed),\n delayed: this._toNumber(delayed),\n }\n }\n\n /**\n * Collect metrics for a single queue and set gauges.\n *\n * Supports:\n * - Bull (default): keys like `bull:<queue>:wait`, `...:active`, `...:completed`, `...:failed`, `...:delayed`\n * - Bee-Queue: keys like `bq:<queue>:waiting`, `...:active`, `...:succeeded`, `...:failed`, `...:delayed`\n *\n * Auto-detects queue type unless `METRICS_QUEUE_TYPE` is set to `bull` or `bee`.\n *\n * @param {string} queueName - Name of the queue\n * @returns {Promise<void>}\n */\n collectSingleQueueMetrics = async queueName => {\n try {\n const queueType = await this._getQueueType(queueName)\n const health =\n queueType === 'bee'\n ? await this._getBeeQueueHealth(queueName)\n : await this._getBullHealth(queueName)\n\n const labels = {\n ...this.getDefaultLabels(),\n queue_name: queueName,\n }\n\n this.queueJobsGauge.set(\n { ...labels, status: 'waiting' },\n health.waiting || 0\n )\n this.queueJobsGauge.set(\n { ...labels, status: 'active' },\n health.active || 0\n )\n this.queueJobsGauge.set(\n { ...labels, status: 'succeeded' },\n health.succeeded || 0\n )\n this.queueJobsGauge.set(\n { ...labels, status: 'failed' },\n health.failed || 0\n )\n this.queueJobsGauge.set(\n { ...labels, status: 'delayed' },\n health.delayed || 0\n )\n } catch (error) {\n console.warn(\n `[queue-metrics] Failed to collect metrics for queue ${queueName}:`,\n error.message\n )\n }\n }\n\n /**\n * Collect metrics for all queues and Redis, then push to Pushgateway\n * @returns {Promise<void>}\n */\n collectQueueMetrics = async () => {\n try {\n const queueNames = this.getConfiguredQueueNames()\n\n await this.collectRedisMetrics()\n await Promise.allSettled(\n queueNames.map(queueName => this.collectSingleQueueMetrics(queueName))\n )\n\n await this.gatewayPush()\n this.clearAllCounters()\n\n if (this.metricsLogValues) {\n const metricObjects = await this.registry.getMetricsAsJSON()\n console.info(\n `[queue-metrics] Collected metrics for ${queueNames.length} queues:`,\n JSON.stringify(metricObjects, null, 2)\n )\n }\n } catch (error) {\n if (\n error.message?.includes('No queues configured') ||\n error.message?.includes('METRICS_APP_REDIS_BQ')\n ) {\n console.error(\n `[queue-metrics] ❌ Configuration error: ${error.message}`\n )\n console.error(\n `[queue-metrics] 💡 Example config: METRICS_APP_REDIS_BQ=\"adalo-compile,adalo-migrations\"`\n )\n } else {\n console.error(\n `[queue-metrics] Failed to collect queue metrics: ${error.message}`\n )\n }\n throw error\n }\n }\n\n /**\n * Start periodic collection.\n * @param {number} [intervalSec=this.intervalSec] - Interval in seconds\n */\n startPush = (intervalSec = this.intervalSec) => {\n this._startPush(intervalSec, () => {\n this.collectQueueMetrics().catch(err => {\n console.error(\n `[queue-metrics] Failed to collect queue & Redis metrics:`,\n err\n )\n })\n })\n }\n\n _setCleanupHandlers = () => {\n process.on('SIGINT', this.cleanup)\n process.on('SIGTERM', this.cleanup)\n }\n\n /**\n * Cleanup queues and exit process.\n * Closes queues then runs Redis metrics cleanup (stop push, delete from VM, close Redis).\n * @returns {Promise<void>}\n */\n cleanup = async () => {\n for (const [queueName, queue] of this.queueCache) {\n try {\n await queue.close()\n } catch (err) {\n console.error(`[queue-metrics] Error closing queue ${queueName}:`, err)\n }\n }\n await super.cleanup()\n }\n}\n\nmodule.exports = { QueueRedisMetricsClient }\n"],"mappings":"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","ignoreList":[]}
|
package/package.json
CHANGED
|
@@ -11,6 +11,7 @@ class QueueRedisMetricsClient extends RedisMetricsClient {
|
|
|
11
11
|
/**
|
|
12
12
|
* @param {Object} options
|
|
13
13
|
* @param {any} options.redisClient - Redis client instance (required)
|
|
14
|
+
* @param {boolean} [options.gracefulShutdownRedis] - Passed to RedisMetricsClient
|
|
14
15
|
* @param {string} [options.appName] - Application name (from BaseMetricsClient)
|
|
15
16
|
* @param {string} [options.dynoId] - Dyno/instance ID (from BaseMetricsClient)
|
|
16
17
|
* @param {string} [options.processType] - Process type (from BaseMetricsClient)
|
|
@@ -23,7 +24,7 @@ class QueueRedisMetricsClient extends RedisMetricsClient {
|
|
|
23
24
|
* @param {function} [options.startupValidation] - Function to validate startup (from BaseMetricsClient)
|
|
24
25
|
* @param {boolean} [options.disablePushgateway] - Disable pushing to Pushgateway (use HTTP scraping instead)
|
|
25
26
|
*/
|
|
26
|
-
constructor({ redisClient, metricsConfig
|
|
27
|
+
constructor({ redisClient, ...metricsConfig } = {}) {
|
|
27
28
|
const getConfiguredQueueNames = () => {
|
|
28
29
|
if (!process.env.METRICS_APP_REDIS_BQ) {
|
|
29
30
|
throw new Error(
|