qdone 2.2.3 → 2.2.4

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.
@@ -26,7 +26,7 @@ async function monitor(queue, save, options) {
26
26
  const opt = (0, defaults_js_1.getOptionsWithDefaults)(options);
27
27
  const queueName = (0, qrlCache_js_1.normalizeQueueName)(queue, opt);
28
28
  debug({ options, opt, queue, queueName });
29
- const data = await getAggregateData(queueName);
29
+ const data = await getAggregateData(queueName, opt);
30
30
  console.log(data);
31
31
  if (save) {
32
32
  if (opt.verbose)
@@ -85,7 +85,7 @@ async function getQueueAge(queueName) {
85
85
  * Metrics (from CloudWatch):
86
86
  * - ApproximateAgeOfOldestMessage: Max
87
87
  */
88
- async function getAggregateData(queueName) {
88
+ async function getAggregateData(queueName, opt) {
89
89
  const { prefix, suffixRegex } = interpretWildcard(queueName);
90
90
  const qrls = await (0, sqs_js_1.getMatchingQueues)(prefix, suffixRegex);
91
91
  // debug({ qrls })
@@ -105,7 +105,19 @@ async function getAggregateData(queueName) {
105
105
  }
106
106
  // Fetch ApproximateAgeOfOldestMessage from CloudWatch (not available via SQS API)
107
107
  // Only query queues with messages to minimize CloudWatch API costs
108
- const ageResults = await Promise.all([...total.contributingQueueNames].map(queue => getQueueAge(queue)));
108
+ // Filter out dead and failed queues for age calculation only — their messages
109
+ // age indefinitely by design, polluting the active age metric.
110
+ // But if the pattern itself targets dead/failed queues, don't filter them out.
111
+ const failSuffix = (opt && opt.failSuffix) || defaults_js_1.defaults.failSuffix;
112
+ const dlqSuffix = (opt && opt.dlqSuffix) || defaults_js_1.defaults.dlqSuffix;
113
+ const strippedPattern = queueName.replace(/\.fifo$/, '');
114
+ const patternTargetsDeadFailed = strippedPattern.endsWith(failSuffix) || strippedPattern.endsWith(dlqSuffix);
115
+ const esc = s => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
116
+ const deadFailedRegex = new RegExp(`(${esc(failSuffix)}|${esc(dlqSuffix)})(\\.fifo)?$`);
117
+ const activeQueueNames = patternTargetsDeadFailed
118
+ ? [...total.contributingQueueNames]
119
+ : [...total.contributingQueueNames].filter(q => !deadFailedRegex.test(q));
120
+ const ageResults = await Promise.all(activeQueueNames.map(queue => getQueueAge(queue)));
109
121
  total.ApproximateAgeOfOldestMessage = Math.max(0, ...ageResults);
110
122
  // debug({ total })
111
123
  // convert set to array
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qdone",
3
- "version": "2.2.3",
3
+ "version": "2.2.4",
4
4
  "description": "A distributed scheduler for SQS",
5
5
  "type": "module",
6
6
  "main": "./index.js",
package/src/cli.js CHANGED
@@ -197,10 +197,11 @@ export async function check (argv, testHook) {
197
197
  }
198
198
 
199
199
  const monitorOptionDefinitions = [
200
- { name: 'save', alias: 's', type: Boolean, description: 'Saves data to CloudWatch' }
200
+ { name: 'save', alias: 's', type: Boolean, description: 'Saves data to CloudWatch' },
201
+ { name: 'dlq-suffix', type: String, description: `Suffix to append to each queue to generate DLQ name [default: ${defaults.dlqSuffix}]` }
201
202
  ]
202
203
 
203
- export async function monitor (argv) {
204
+ export async function monitor (argv, testHook) {
204
205
  const optionDefinitions = [].concat(monitorOptionDefinitions, globalOptionDefinitions)
205
206
  const usageSections = [
206
207
  { content: 'usage: qdone monitor <queuePattern> ', raw: true },
@@ -234,7 +235,8 @@ export async function monitor (argv) {
234
235
 
235
236
  // Load module after AWS global load
236
237
  setupAWS(options)
237
- const { monitor } = await import('./monitor.js')
238
+ const { monitor: monitorOriginal } = await import('./monitor.js')
239
+ const monitor = testHook || monitorOriginal
238
240
  return monitor(queue, options.save, options)
239
241
  }
240
242
 
package/src/monitor.js CHANGED
@@ -5,7 +5,7 @@
5
5
  import { getMatchingQueues, getQueueAttributes } from './sqs.js'
6
6
  import { putAggregateData, getCloudWatchClient } from './cloudWatch.js'
7
7
  import { GetMetricStatisticsCommand } from '@aws-sdk/client-cloudwatch'
8
- import { getOptionsWithDefaults } from './defaults.js'
8
+ import { getOptionsWithDefaults, defaults } from './defaults.js'
9
9
  import { normalizeQueueName } from './qrlCache.js'
10
10
  import Debug from 'debug'
11
11
  const debug = Debug('qdone:monitor')
@@ -18,7 +18,7 @@ export async function monitor (queue, save, options) {
18
18
  const opt = getOptionsWithDefaults(options)
19
19
  const queueName = normalizeQueueName(queue, opt)
20
20
  debug({ options, opt, queue, queueName })
21
- const data = await getAggregateData(queueName)
21
+ const data = await getAggregateData(queueName, opt)
22
22
  console.log(data)
23
23
  if (save) {
24
24
  if (opt.verbose) process.stderr.write('Saving to CloudWatch...')
@@ -76,7 +76,7 @@ export async function getQueueAge (queueName) {
76
76
  * Metrics (from CloudWatch):
77
77
  * - ApproximateAgeOfOldestMessage: Max
78
78
  */
79
- export async function getAggregateData (queueName) {
79
+ export async function getAggregateData (queueName, opt) {
80
80
  const { prefix, suffixRegex } = interpretWildcard(queueName)
81
81
  const qrls = await getMatchingQueues(prefix, suffixRegex)
82
82
  // debug({ qrls })
@@ -97,8 +97,21 @@ export async function getAggregateData (queueName) {
97
97
 
98
98
  // Fetch ApproximateAgeOfOldestMessage from CloudWatch (not available via SQS API)
99
99
  // Only query queues with messages to minimize CloudWatch API costs
100
+ // Filter out dead and failed queues for age calculation only — their messages
101
+ // age indefinitely by design, polluting the active age metric.
102
+ // But if the pattern itself targets dead/failed queues, don't filter them out.
103
+ const failSuffix = (opt && opt.failSuffix) || defaults.failSuffix
104
+ const dlqSuffix = (opt && opt.dlqSuffix) || defaults.dlqSuffix
105
+ const strippedPattern = queueName.replace(/\.fifo$/, '')
106
+ const patternTargetsDeadFailed = strippedPattern.endsWith(failSuffix) || strippedPattern.endsWith(dlqSuffix)
107
+ const esc = s => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
108
+ const deadFailedRegex = new RegExp(`(${esc(failSuffix)}|${esc(dlqSuffix)})(\\.fifo)?$`)
109
+ const activeQueueNames = patternTargetsDeadFailed
110
+ ? [...total.contributingQueueNames]
111
+ : [...total.contributingQueueNames].filter(q => !deadFailedRegex.test(q))
112
+
100
113
  const ageResults = await Promise.all(
101
- [...total.contributingQueueNames].map(queue => getQueueAge(queue))
114
+ activeQueueNames.map(queue => getQueueAge(queue))
102
115
  )
103
116
  total.ApproximateAgeOfOldestMessage = Math.max(0, ...ageResults)
104
117