qdone 2.0.51-alpha → 2.0.52-alpha
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/README.md +2 -7
- package/commonjs/src/defaults.js +13 -3
- package/commonjs/src/idleQueues.js +20 -42
- package/commonjs/src/monitor.js +3 -1
- package/package.json +1 -1
- package/src/cli.js +1 -3
- package/src/defaults.js +11 -2
- package/src/idleQueues.js +18 -40
- package/src/monitor.js +2 -1
- package/npm-shrinkwrap.json +0 -16000
package/README.md
CHANGED
|
@@ -561,13 +561,8 @@ If a queue name ends with the * (wildcard) character, worker will listen on all
|
|
|
561
561
|
|
|
562
562
|
-o, --idle-for number Minutes of inactivity after which a queue is considered
|
|
563
563
|
idle. [default: 60]
|
|
564
|
-
--delete Delete the queue if it is idle
|
|
565
|
-
|
|
566
|
-
--unpair Treat queues and their fail queues as independent. By default
|
|
567
|
-
they are treated as a unit.
|
|
568
|
-
--include-failed When using '*' do not ignore fail queues. This option only
|
|
569
|
-
applies if you use --unpair. Otherwise, queues and fail queues
|
|
570
|
-
are treated as a unit.
|
|
564
|
+
--delete Delete the queue if it is idle along with its corresponding
|
|
565
|
+
fail queue and dlq.
|
|
571
566
|
--prefix string Prefix to place at the front of each SQS queue name [default: qdone_]
|
|
572
567
|
--fail-suffix string Suffix to append to each queue to generate fail queue name [default: _failed]
|
|
573
568
|
--region string AWS region for Queues [default: us-east-1]
|
package/commonjs/src/defaults.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.setupVerbose = exports.setupAWS = exports.getOptionsWithDefaults = exports.validateMessageOptions = exports.validateInteger = exports.defaults = void 0;
|
|
3
|
+
exports.setupVerbose = exports.setupAWS = exports.getOptionsWithDefaults = exports.validateMessageOptions = exports.validateQueueName = exports.validateInteger = exports.defaults = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* Default options for qdone. Accepts a command line options object and
|
|
6
6
|
* returns nicely-named options.
|
|
@@ -46,7 +46,6 @@ exports.defaults = Object.freeze({
|
|
|
46
46
|
// Idle Queues
|
|
47
47
|
idleFor: 60,
|
|
48
48
|
delete: false,
|
|
49
|
-
unpair: false,
|
|
50
49
|
// Check
|
|
51
50
|
create: false,
|
|
52
51
|
overwrite: false
|
|
@@ -58,6 +57,14 @@ function validateInteger(opt, name) {
|
|
|
58
57
|
return parsed;
|
|
59
58
|
}
|
|
60
59
|
exports.validateInteger = validateInteger;
|
|
60
|
+
function validateQueueName(opt, name) {
|
|
61
|
+
if (typeof name !== 'string')
|
|
62
|
+
throw new Error(`${name} must be a string.`);
|
|
63
|
+
if (!name.match(/^[a-z0-9-_]+$/i))
|
|
64
|
+
throw new Error(`${name} can contain only numbers, letters, hypens and underscores.`);
|
|
65
|
+
return name;
|
|
66
|
+
}
|
|
67
|
+
exports.validateQueueName = validateQueueName;
|
|
61
68
|
function validateMessageOptions(messageOptions) {
|
|
62
69
|
const validKeys = ['deduplicationId', 'groupId'];
|
|
63
70
|
if (typeof messageOptions === 'object' &&
|
|
@@ -128,7 +135,6 @@ function getOptionsWithDefaults(options) {
|
|
|
128
135
|
// Idle Queues
|
|
129
136
|
idleFor: options.idleFor || options['idle-for'] || process.env.QDONE_IDLE_FOR || exports.defaults.idleFor,
|
|
130
137
|
delete: options.delete || process.env.QDONE_DELETE === 'true' || exports.defaults.delete,
|
|
131
|
-
unpair: options.unpair || process.env.QDONE_UNPAIR === 'true' || exports.defaults.unpair,
|
|
132
138
|
// Check
|
|
133
139
|
create: options.create || process.env.QDONE_CREATE === 'true' || exports.defaults.create,
|
|
134
140
|
overwrite: options.overwrite || process.env.QDONE_OVERWRITE === 'true' || exports.defaults.overwrite
|
|
@@ -148,6 +154,10 @@ function getOptionsWithDefaults(options) {
|
|
|
148
154
|
opt.maxConcurrentJobs = validateInteger(opt, 'maxConcurrentJobs');
|
|
149
155
|
opt.maxMemoryPercent = validateInteger(opt, 'maxMemoryPercent');
|
|
150
156
|
opt.idleFor = validateInteger(opt, 'idleFor');
|
|
157
|
+
validateQueueName(opt, 'region');
|
|
158
|
+
validateQueueName(opt, 'prefix');
|
|
159
|
+
validateQueueName(opt, 'failSuffix');
|
|
160
|
+
validateQueueName(opt, 'dlqSuffix');
|
|
151
161
|
// Validate dedup args
|
|
152
162
|
if (opt.externalDedup && !opt.cacheUri)
|
|
153
163
|
throw new Error('--external-dedup requires the --cache-uri argument');
|
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.idleQueues = exports.
|
|
6
|
+
exports.idleQueues = exports.stripSuffixes = exports.processQueueSet = exports.deleteQueue = exports.checkIdle = exports.getMetric = exports.cheapIdleCheck = exports._cheapIdleCheck = exports.attributeNames = void 0;
|
|
7
7
|
/**
|
|
8
8
|
* Implementation of checks and caching of checks to determine if queues are idle.
|
|
9
9
|
*/
|
|
@@ -187,35 +187,6 @@ async function deleteQueue(qname, qrl, opt) {
|
|
|
187
187
|
};
|
|
188
188
|
}
|
|
189
189
|
exports.deleteQueue = deleteQueue;
|
|
190
|
-
/**
|
|
191
|
-
* Processes a single queue, checking for idle, deleting if applicable.
|
|
192
|
-
*/
|
|
193
|
-
async function processQueue(qname, qrl, opt) {
|
|
194
|
-
const result = await checkIdle(qname, qrl, opt);
|
|
195
|
-
debug(qname, result);
|
|
196
|
-
// Queue is active
|
|
197
|
-
if (!result.idle) {
|
|
198
|
-
// Notify and return
|
|
199
|
-
if (opt.verbose)
|
|
200
|
-
console.error(chalk_1.default.blue('Queue ') + qname.slice(opt.prefix.length) + chalk_1.default.blue(' has been ') + 'active' + chalk_1.default.blue(' in the last ') + opt.idleFor + chalk_1.default.blue(' minutes.'));
|
|
201
|
-
return result;
|
|
202
|
-
}
|
|
203
|
-
// Queue is idle
|
|
204
|
-
if (opt.verbose)
|
|
205
|
-
console.error(chalk_1.default.blue('Queue ') + qname.slice(opt.prefix.length) + chalk_1.default.blue(' has been ') + 'idle' + chalk_1.default.blue(' for the last ') + opt.idleFor + chalk_1.default.blue(' minutes.'));
|
|
206
|
-
if (opt.delete) {
|
|
207
|
-
const deleteResult = await deleteQueue(qname, qrl, opt);
|
|
208
|
-
const resultIncludingDelete = Object.assign(result, {
|
|
209
|
-
deleted: deleteResult.deleted,
|
|
210
|
-
apiCalls: {
|
|
211
|
-
SQS: result.apiCalls.SQS + deleteResult.apiCalls.SQS,
|
|
212
|
-
CloudWatch: result.apiCalls.CloudWatch + deleteResult.apiCalls.CloudWatch
|
|
213
|
-
}
|
|
214
|
-
});
|
|
215
|
-
return resultIncludingDelete;
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
exports.processQueue = processQueue;
|
|
219
190
|
/**
|
|
220
191
|
* Processes a queue and its fail and delete queue, treating them as a unit.
|
|
221
192
|
*/
|
|
@@ -311,6 +282,14 @@ async function processQueueSet(qname, qrl, opt) {
|
|
|
311
282
|
}
|
|
312
283
|
exports.processQueueSet = processQueueSet;
|
|
313
284
|
//
|
|
285
|
+
// Strips failed and dlq suffix from a queue name or URL
|
|
286
|
+
//
|
|
287
|
+
function stripSuffixes(queueName, opt) {
|
|
288
|
+
const suffixFinder = new RegExp(`(${opt.dlqSuffix}|${opt.failSuffix}){1}(|${qrlCache_js_1.fifoSuffix})$`);
|
|
289
|
+
return queueName.replace(suffixFinder, '$2');
|
|
290
|
+
}
|
|
291
|
+
exports.stripSuffixes = stripSuffixes;
|
|
292
|
+
//
|
|
314
293
|
// Resolve queues for listening loop listen
|
|
315
294
|
//
|
|
316
295
|
async function idleQueues(queues, options) {
|
|
@@ -324,17 +303,18 @@ async function idleQueues(queues, options) {
|
|
|
324
303
|
console.error(chalk_1.default.blue(' done'));
|
|
325
304
|
console.error();
|
|
326
305
|
}
|
|
327
|
-
// Filter out
|
|
306
|
+
// Filter out failed and dead queues, but if we have an orphaned fail or
|
|
307
|
+
// dead queue, keep the original parent queue name so that orphans can be
|
|
308
|
+
// deleted.
|
|
309
|
+
const queueNames = new Set();
|
|
328
310
|
const filteredEntries = entries.filter(entry => {
|
|
329
|
-
const
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
const isFifoDead = entry.qname.endsWith(sufFifoDead);
|
|
337
|
-
return opt.includeFailed ? true : (!isFail && !isFifoFail && !isDead && !isFifoDead);
|
|
311
|
+
const stripped = stripSuffixes(entry.qname, opt);
|
|
312
|
+
if (queueNames.has(stripped))
|
|
313
|
+
return false;
|
|
314
|
+
queueNames.add(stripped);
|
|
315
|
+
entry.qname = stripped;
|
|
316
|
+
entry.qrl = stripSuffixes(entry.qrl, opt);
|
|
317
|
+
return true;
|
|
338
318
|
});
|
|
339
319
|
// But only if we have queues to remove
|
|
340
320
|
if (filteredEntries.length) {
|
|
@@ -344,8 +324,6 @@ async function idleQueues(queues, options) {
|
|
|
344
324
|
console.error();
|
|
345
325
|
}
|
|
346
326
|
// Check each queue in parallel
|
|
347
|
-
if (opt.unpair)
|
|
348
|
-
return Promise.all(filteredEntries.map(e => processQueue(e.qname, e.qrl, opt)));
|
|
349
327
|
return Promise.all(filteredEntries.map(e => processQueueSet(e.qname, e.qrl, opt)));
|
|
350
328
|
}
|
|
351
329
|
// Otherwise, let caller know
|
package/commonjs/src/monitor.js
CHANGED
|
@@ -17,9 +17,11 @@ const debug = (0, debug_1.default)('qdone:monitor');
|
|
|
17
17
|
* Splits a queue name with a single wildcard into prefix and suffix regex.
|
|
18
18
|
*/
|
|
19
19
|
async function monitor(queue, save, options) {
|
|
20
|
+
if (queue.endsWith('.fifo'))
|
|
21
|
+
options.fifo = true;
|
|
20
22
|
const opt = (0, defaults_js_1.getOptionsWithDefaults)(options);
|
|
21
23
|
const queueName = (0, qrlCache_js_1.normalizeQueueName)(queue, opt);
|
|
22
|
-
debug({ opt, queueName });
|
|
24
|
+
debug({ options, opt, queue, queueName });
|
|
23
25
|
const data = await getAggregateData(queueName);
|
|
24
26
|
console.log(data);
|
|
25
27
|
if (save) {
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -440,9 +440,7 @@ export async function worker (argv, testHook) {
|
|
|
440
440
|
export async function idleQueues (argv, testHook) {
|
|
441
441
|
const optionDefinitions = [
|
|
442
442
|
{ name: 'idle-for', alias: 'o', type: Number, defaultValue: defaults.idleFor, description: `Minutes of inactivity after which a queue is considered idle. [default: ${defaults.idleFor}]` },
|
|
443
|
-
{ name: 'delete', type: Boolean, description: 'Delete the queue if it is idle
|
|
444
|
-
{ name: 'unpair', type: Boolean, description: 'Treat queues and their fail queues as independent. By default they are treated as a unit.' },
|
|
445
|
-
{ name: 'include-failed', type: Boolean, description: 'When using \'*\' do not ignore fail queues. This option only applies if you use --unpair. Otherwise, queues and fail queues are treated as a unit.' }
|
|
443
|
+
{ name: 'delete', type: Boolean, description: 'Delete the queue if it is idle along with its corresponding fail queue and dlq.' }
|
|
446
444
|
].concat(globalOptionDefinitions)
|
|
447
445
|
|
|
448
446
|
const usageSections = [
|
package/src/defaults.js
CHANGED
|
@@ -47,7 +47,6 @@ export const defaults = Object.freeze({
|
|
|
47
47
|
// Idle Queues
|
|
48
48
|
idleFor: 60,
|
|
49
49
|
delete: false,
|
|
50
|
-
unpair: false,
|
|
51
50
|
|
|
52
51
|
// Check
|
|
53
52
|
create: false,
|
|
@@ -60,6 +59,12 @@ export function validateInteger (opt, name) {
|
|
|
60
59
|
return parsed
|
|
61
60
|
}
|
|
62
61
|
|
|
62
|
+
export function validateQueueName (opt, name) {
|
|
63
|
+
if (typeof name !== 'string') throw new Error(`${name} must be a string.`)
|
|
64
|
+
if (!name.match(/^[a-z0-9-_]+$/i)) throw new Error(`${name} can contain only numbers, letters, hypens and underscores.`)
|
|
65
|
+
return name
|
|
66
|
+
}
|
|
67
|
+
|
|
63
68
|
export function validateMessageOptions (messageOptions) {
|
|
64
69
|
const validKeys = ['deduplicationId', 'groupId']
|
|
65
70
|
if (typeof messageOptions === 'object' &&
|
|
@@ -134,7 +139,6 @@ export function getOptionsWithDefaults (options) {
|
|
|
134
139
|
// Idle Queues
|
|
135
140
|
idleFor: options.idleFor || options['idle-for'] || process.env.QDONE_IDLE_FOR || defaults.idleFor,
|
|
136
141
|
delete: options.delete || process.env.QDONE_DELETE === 'true' || defaults.delete,
|
|
137
|
-
unpair: options.unpair || process.env.QDONE_UNPAIR === 'true' || defaults.unpair,
|
|
138
142
|
|
|
139
143
|
// Check
|
|
140
144
|
create: options.create || process.env.QDONE_CREATE === 'true' || defaults.create,
|
|
@@ -158,6 +162,11 @@ export function getOptionsWithDefaults (options) {
|
|
|
158
162
|
opt.maxMemoryPercent = validateInteger(opt, 'maxMemoryPercent')
|
|
159
163
|
opt.idleFor = validateInteger(opt, 'idleFor')
|
|
160
164
|
|
|
165
|
+
validateQueueName(opt, 'region')
|
|
166
|
+
validateQueueName(opt, 'prefix')
|
|
167
|
+
validateQueueName(opt, 'failSuffix')
|
|
168
|
+
validateQueueName(opt, 'dlqSuffix')
|
|
169
|
+
|
|
161
170
|
// Validate dedup args
|
|
162
171
|
if (opt.externalDedup && !opt.cacheUri) throw new Error('--external-dedup requires the --cache-uri argument')
|
|
163
172
|
if (opt.externalDedup && (opt.dedupPeriod < 1)) throw new Error('--external-dedup of redis requires a --dedup-period > 1 second')
|
package/src/idleQueues.js
CHANGED
|
@@ -186,35 +186,6 @@ export async function deleteQueue (qname, qrl, opt) {
|
|
|
186
186
|
}
|
|
187
187
|
}
|
|
188
188
|
|
|
189
|
-
/**
|
|
190
|
-
* Processes a single queue, checking for idle, deleting if applicable.
|
|
191
|
-
*/
|
|
192
|
-
export async function processQueue (qname, qrl, opt) {
|
|
193
|
-
const result = await checkIdle(qname, qrl, opt)
|
|
194
|
-
debug(qname, result)
|
|
195
|
-
|
|
196
|
-
// Queue is active
|
|
197
|
-
if (!result.idle) {
|
|
198
|
-
// Notify and return
|
|
199
|
-
if (opt.verbose) console.error(chalk.blue('Queue ') + qname.slice(opt.prefix.length) + chalk.blue(' has been ') + 'active' + chalk.blue(' in the last ') + opt.idleFor + chalk.blue(' minutes.'))
|
|
200
|
-
return result
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
// Queue is idle
|
|
204
|
-
if (opt.verbose) console.error(chalk.blue('Queue ') + qname.slice(opt.prefix.length) + chalk.blue(' has been ') + 'idle' + chalk.blue(' for the last ') + opt.idleFor + chalk.blue(' minutes.'))
|
|
205
|
-
if (opt.delete) {
|
|
206
|
-
const deleteResult = await deleteQueue(qname, qrl, opt)
|
|
207
|
-
const resultIncludingDelete = Object.assign(result, {
|
|
208
|
-
deleted: deleteResult.deleted,
|
|
209
|
-
apiCalls: {
|
|
210
|
-
SQS: result.apiCalls.SQS + deleteResult.apiCalls.SQS,
|
|
211
|
-
CloudWatch: result.apiCalls.CloudWatch + deleteResult.apiCalls.CloudWatch
|
|
212
|
-
}
|
|
213
|
-
})
|
|
214
|
-
return resultIncludingDelete
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
|
|
218
189
|
/**
|
|
219
190
|
* Processes a queue and its fail and delete queue, treating them as a unit.
|
|
220
191
|
*/
|
|
@@ -308,6 +279,14 @@ export async function processQueueSet (qname, qrl, opt) {
|
|
|
308
279
|
return result
|
|
309
280
|
}
|
|
310
281
|
|
|
282
|
+
//
|
|
283
|
+
// Strips failed and dlq suffix from a queue name or URL
|
|
284
|
+
//
|
|
285
|
+
export function stripSuffixes (queueName, opt) {
|
|
286
|
+
const suffixFinder = new RegExp(`(${opt.dlqSuffix}|${opt.failSuffix}){1}(|${fifoSuffix})$`)
|
|
287
|
+
return queueName.replace(suffixFinder, '$2')
|
|
288
|
+
}
|
|
289
|
+
|
|
311
290
|
//
|
|
312
291
|
// Resolve queues for listening loop listen
|
|
313
292
|
//
|
|
@@ -322,17 +301,17 @@ export async function idleQueues (queues, options) {
|
|
|
322
301
|
console.error()
|
|
323
302
|
}
|
|
324
303
|
|
|
325
|
-
// Filter out
|
|
304
|
+
// Filter out failed and dead queues, but if we have an orphaned fail or
|
|
305
|
+
// dead queue, keep the original parent queue name so that orphans can be
|
|
306
|
+
// deleted.
|
|
307
|
+
const queueNames = new Set()
|
|
326
308
|
const filteredEntries = entries.filter(entry => {
|
|
327
|
-
const
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
const isDead = entry.qname.endsWith(sufDead)
|
|
334
|
-
const isFifoDead = entry.qname.endsWith(sufFifoDead)
|
|
335
|
-
return opt.includeFailed ? true : (!isFail && !isFifoFail && !isDead && !isFifoDead)
|
|
309
|
+
const stripped = stripSuffixes(entry.qname, opt)
|
|
310
|
+
if (queueNames.has(stripped)) return false
|
|
311
|
+
queueNames.add(stripped)
|
|
312
|
+
entry.qname = stripped
|
|
313
|
+
entry.qrl = stripSuffixes(entry.qrl, opt)
|
|
314
|
+
return true
|
|
336
315
|
})
|
|
337
316
|
|
|
338
317
|
// But only if we have queues to remove
|
|
@@ -345,7 +324,6 @@ export async function idleQueues (queues, options) {
|
|
|
345
324
|
console.error()
|
|
346
325
|
}
|
|
347
326
|
// Check each queue in parallel
|
|
348
|
-
if (opt.unpair) return Promise.all(filteredEntries.map(e => processQueue(e.qname, e.qrl, opt)))
|
|
349
327
|
return Promise.all(filteredEntries.map(e => processQueueSet(e.qname, e.qrl, opt)))
|
|
350
328
|
}
|
|
351
329
|
|
package/src/monitor.js
CHANGED
|
@@ -13,9 +13,10 @@ const debug = Debug('qdone:monitor')
|
|
|
13
13
|
* Splits a queue name with a single wildcard into prefix and suffix regex.
|
|
14
14
|
*/
|
|
15
15
|
export async function monitor (queue, save, options) {
|
|
16
|
+
if (queue.endsWith('.fifo')) options.fifo = true
|
|
16
17
|
const opt = getOptionsWithDefaults(options)
|
|
17
18
|
const queueName = normalizeQueueName(queue, opt)
|
|
18
|
-
debug({ opt, queueName })
|
|
19
|
+
debug({ options, opt, queue, queueName })
|
|
19
20
|
const data = await getAggregateData(queueName)
|
|
20
21
|
console.log(data)
|
|
21
22
|
if (save) {
|