qdone 1.6.0 → 2.0.0-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 +9 -1
- package/commonjs/index.js +10 -0
- package/commonjs/package.json +3 -0
- package/commonjs/src/cache.js +142 -0
- package/commonjs/src/cloudWatch.js +148 -0
- package/commonjs/src/consumer.js +483 -0
- package/commonjs/src/defaults.js +107 -0
- package/commonjs/src/enqueue.js +498 -0
- package/commonjs/src/idleQueues.js +466 -0
- package/commonjs/src/qrlCache.js +250 -0
- package/commonjs/src/sqs.js +160 -0
- package/npm-shrinkwrap.json +17598 -264
- package/package.json +41 -29
- package/src/bin.js +3 -0
- package/src/cache.js +21 -25
- package/src/cli.js +269 -181
- package/src/cloudWatch.js +97 -0
- package/src/consumer.js +346 -0
- package/src/defaults.js +114 -0
- package/src/enqueue.js +239 -196
- package/src/idleQueues.js +242 -223
- package/src/monitor.js +53 -0
- package/src/qrlCache.js +110 -83
- package/src/sentry.js +30 -0
- package/src/sqs.js +73 -0
- package/src/worker.js +197 -202
- package/.DS_Store +0 -0
- package/.coveralls.yml +0 -2
- package/.travis.yml +0 -17
- package/CHANGELOG.md +0 -107
- package/dump.rdb +0 -0
- package/index.js +0 -6
- package/package-lock.json.old +0 -3939
- package/qdone +0 -2
- package/test/fixtures/test-child-kill-linux.sh +0 -9
- package/test/fixtures/test-fifo01-x24.batch +0 -24
- package/test/fixtures/test-too-big-1.batch +0 -10
- package/test/fixtures/test-unique01-x24.batch +0 -24
- package/test/fixtures/test-unique02-x24.batch +0 -24
- package/test/fixtures/test-unique24-x24.batch +0 -24
- package/test/fixtures/test-unique24-x240.batch +0 -240
- package/test/test.cache.js +0 -61
- package/test/test.cli.js +0 -1609
|
@@ -0,0 +1,466 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
13
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
|
+
function step(op) {
|
|
16
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
17
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
18
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
19
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
20
|
+
switch (op[0]) {
|
|
21
|
+
case 0: case 1: t = op; break;
|
|
22
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
23
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
24
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
25
|
+
default:
|
|
26
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
27
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
28
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
29
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
30
|
+
if (t[2]) _.ops.pop();
|
|
31
|
+
_.trys.pop(); continue;
|
|
32
|
+
}
|
|
33
|
+
op = body.call(thisArg, _);
|
|
34
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
35
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
39
|
+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
40
|
+
if (ar || !(i in from)) {
|
|
41
|
+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
42
|
+
ar[i] = from[i];
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
|
46
|
+
};
|
|
47
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
48
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
49
|
+
};
|
|
50
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
51
|
+
exports.idleQueues = exports.processQueuePair = exports.processQueue = exports.deleteQueue = exports.checkIdle = exports.getMetric = exports.cheapIdleCheck = exports._cheapIdleCheck = exports.attributeNames = void 0;
|
|
52
|
+
/**
|
|
53
|
+
* Implementation of checks and caching of checks to determine if queues are idle.
|
|
54
|
+
*/
|
|
55
|
+
var chalk_1 = __importDefault(require("chalk"));
|
|
56
|
+
var sqs_js_1 = require("./sqs.js");
|
|
57
|
+
var cloudWatch_js_1 = require("./cloudWatch.js");
|
|
58
|
+
var defaults_js_1 = require("./defaults.js");
|
|
59
|
+
var client_sqs_1 = require("@aws-sdk/client-sqs");
|
|
60
|
+
var client_cloudwatch_1 = require("@aws-sdk/client-cloudwatch");
|
|
61
|
+
var qrlCache_js_1 = require("./qrlCache.js");
|
|
62
|
+
var cache_js_1 = require("./cache.js");
|
|
63
|
+
// const AWS = require('aws-sdk')
|
|
64
|
+
var debug_1 = __importDefault(require("debug"));
|
|
65
|
+
var debug = (0, debug_1.default)('qdone:idleQueues');
|
|
66
|
+
// Queue attributes we check to determine idle
|
|
67
|
+
exports.attributeNames = [
|
|
68
|
+
'ApproximateNumberOfMessages',
|
|
69
|
+
'ApproximateNumberOfMessagesNotVisible',
|
|
70
|
+
'ApproximateNumberOfMessagesDelayed'
|
|
71
|
+
];
|
|
72
|
+
// CloudWatch metrics we check to determine idle
|
|
73
|
+
var metricNames = [
|
|
74
|
+
'NumberOfMessagesSent',
|
|
75
|
+
'NumberOfMessagesReceived',
|
|
76
|
+
'NumberOfMessagesDeleted',
|
|
77
|
+
'ApproximateNumberOfMessagesVisible',
|
|
78
|
+
'ApproximateNumberOfMessagesNotVisible',
|
|
79
|
+
'ApproximateNumberOfMessagesDelayed',
|
|
80
|
+
// 'NumberOfEmptyReceives',
|
|
81
|
+
'ApproximateAgeOfOldestMessage'
|
|
82
|
+
];
|
|
83
|
+
/**
|
|
84
|
+
* Actual SQS call, used in conjunction with cache.
|
|
85
|
+
*/
|
|
86
|
+
function _cheapIdleCheck(qname, qrl, opt) {
|
|
87
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
88
|
+
var client, cmd, data, result;
|
|
89
|
+
return __generator(this, function (_a) {
|
|
90
|
+
switch (_a.label) {
|
|
91
|
+
case 0:
|
|
92
|
+
client = (0, sqs_js_1.getSQSClient)();
|
|
93
|
+
cmd = new client_sqs_1.GetQueueAttributesCommand({ AttributeNames: exports.attributeNames, QueueUrl: qrl });
|
|
94
|
+
return [4 /*yield*/, client.send(cmd)
|
|
95
|
+
// debug('data', data)
|
|
96
|
+
];
|
|
97
|
+
case 1:
|
|
98
|
+
data = _a.sent();
|
|
99
|
+
result = data.Attributes;
|
|
100
|
+
result.queue = qname.slice(opt.prefix.length);
|
|
101
|
+
// We are idle if all the messages attributes are zero
|
|
102
|
+
result.idle = exports.attributeNames.filter(function (k) { return result[k] === '0'; }).length === exports.attributeNames.length;
|
|
103
|
+
return [2 /*return*/, { result: result, SQS: 1 }];
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
exports._cheapIdleCheck = _cheapIdleCheck;
|
|
109
|
+
/**
|
|
110
|
+
* Gets queue attributes from the SQS api and assesses whether queue is idle
|
|
111
|
+
* at this immediate moment.
|
|
112
|
+
*/
|
|
113
|
+
function cheapIdleCheck(qname, qrl, opt) {
|
|
114
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
115
|
+
var key, cacheResult, _a, result, SQS, ok;
|
|
116
|
+
return __generator(this, function (_b) {
|
|
117
|
+
switch (_b.label) {
|
|
118
|
+
case 0:
|
|
119
|
+
// Just call the API if we don't have a cache
|
|
120
|
+
if (!opt.cacheUri)
|
|
121
|
+
return [2 /*return*/, _cheapIdleCheck(qname, qrl, opt)
|
|
122
|
+
// Otherwise check cache
|
|
123
|
+
];
|
|
124
|
+
key = 'cheap-idle-check:' + qrl;
|
|
125
|
+
return [4 /*yield*/, (0, cache_js_1.getCache)(key, opt)];
|
|
126
|
+
case 1:
|
|
127
|
+
cacheResult = _b.sent();
|
|
128
|
+
debug({ cacheResult: cacheResult });
|
|
129
|
+
if (!cacheResult) return [3 /*break*/, 2];
|
|
130
|
+
debug({ action: 'return resolved' });
|
|
131
|
+
return [2 /*return*/, { result: cacheResult, SQS: 0 }];
|
|
132
|
+
case 2:
|
|
133
|
+
// Cache miss, make call
|
|
134
|
+
debug({ action: 'do real check' });
|
|
135
|
+
return [4 /*yield*/, _cheapIdleCheck(qname, qrl, opt)];
|
|
136
|
+
case 3:
|
|
137
|
+
_a = _b.sent(), result = _a.result, SQS = _a.SQS;
|
|
138
|
+
debug({ action: 'setCache', key: key, result: result });
|
|
139
|
+
return [4 /*yield*/, (0, cache_js_1.setCache)(key, result, opt)];
|
|
140
|
+
case 4:
|
|
141
|
+
ok = _b.sent();
|
|
142
|
+
debug({ action: 'return result of set cache', ok: ok });
|
|
143
|
+
return [2 /*return*/, { result: result, SQS: SQS }];
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
exports.cheapIdleCheck = cheapIdleCheck;
|
|
149
|
+
/**
|
|
150
|
+
* Gets a single metric from the CloudWatch api.
|
|
151
|
+
*/
|
|
152
|
+
function getMetric(qname, qrl, metricName, opt) {
|
|
153
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
154
|
+
var now, params, client, cmd, data;
|
|
155
|
+
var _a;
|
|
156
|
+
return __generator(this, function (_b) {
|
|
157
|
+
switch (_b.label) {
|
|
158
|
+
case 0:
|
|
159
|
+
debug('getMetric', qname, qrl, metricName);
|
|
160
|
+
now = new Date();
|
|
161
|
+
params = {
|
|
162
|
+
StartTime: new Date(now.getTime() - 1000 * 60 * opt.idleFor),
|
|
163
|
+
EndTime: now,
|
|
164
|
+
MetricName: metricName,
|
|
165
|
+
Namespace: 'AWS/SQS',
|
|
166
|
+
Period: 3600,
|
|
167
|
+
Dimensions: [{ Name: 'QueueName', Value: qname }],
|
|
168
|
+
Statistics: ['Sum']
|
|
169
|
+
// Unit: ['']
|
|
170
|
+
};
|
|
171
|
+
client = (0, cloudWatch_js_1.getCloudWatchClient)();
|
|
172
|
+
cmd = new client_cloudwatch_1.GetMetricStatisticsCommand(params);
|
|
173
|
+
return [4 /*yield*/, client.send(cmd)];
|
|
174
|
+
case 1:
|
|
175
|
+
data = _b.sent();
|
|
176
|
+
debug('getMetric data', data);
|
|
177
|
+
return [2 /*return*/, (_a = {},
|
|
178
|
+
_a[metricName] = data.Datapoints.map(function (d) { return d.Sum; }).reduce(function (a, b) { return a + b; }, 0),
|
|
179
|
+
_a)];
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
exports.getMetric = getMetric;
|
|
185
|
+
/**
|
|
186
|
+
* Checks if a single queue is idle. First queries the cheap ($0.40/1M) SQS API and
|
|
187
|
+
* continues to the expensive ($10/1M) CloudWatch API, checking to make sure there
|
|
188
|
+
* were no messages in the queue in the specified time period. Only if all relevant
|
|
189
|
+
* metrics show no messages, is it ok to delete the queue.
|
|
190
|
+
*
|
|
191
|
+
* Realistically, the number of CloudWatch calls will depend on usage patterns, but
|
|
192
|
+
* I see a ~70% reduction in calls by checking metrics in the given order.
|
|
193
|
+
* We could randomize the order, but for my test use case, it's always cheaper
|
|
194
|
+
* to check NumberOfMessagesSent first, and is the primary indicator of use.
|
|
195
|
+
*/
|
|
196
|
+
function checkIdle(qname, qrl, opt) {
|
|
197
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
198
|
+
var _a, cheapResult, SQS, apiCalls, results, idle, _i, metricNames_1, metricName, result, stats;
|
|
199
|
+
return __generator(this, function (_b) {
|
|
200
|
+
switch (_b.label) {
|
|
201
|
+
case 0:
|
|
202
|
+
// Do the cheap check first to make sure there is no data in flight at the moment
|
|
203
|
+
debug('checkIdle', qname, qrl);
|
|
204
|
+
return [4 /*yield*/, cheapIdleCheck(qname, qrl, opt)];
|
|
205
|
+
case 1:
|
|
206
|
+
_a = _b.sent(), cheapResult = _a.result, SQS = _a.SQS;
|
|
207
|
+
debug('cheapResult', cheapResult);
|
|
208
|
+
// Short circuit further calls if cheap result shows data
|
|
209
|
+
if (cheapResult.idle === false) {
|
|
210
|
+
return [2 /*return*/, {
|
|
211
|
+
queue: qname.slice(opt.prefix.length),
|
|
212
|
+
cheap: cheapResult,
|
|
213
|
+
idle: false,
|
|
214
|
+
apiCalls: { SQS: SQS, CloudWatch: 0 }
|
|
215
|
+
}];
|
|
216
|
+
}
|
|
217
|
+
apiCalls = { SQS: 1, CloudWatch: 0 };
|
|
218
|
+
results = [];
|
|
219
|
+
idle = true;
|
|
220
|
+
_i = 0, metricNames_1 = metricNames;
|
|
221
|
+
_b.label = 2;
|
|
222
|
+
case 2:
|
|
223
|
+
if (!(_i < metricNames_1.length)) return [3 /*break*/, 5];
|
|
224
|
+
metricName = metricNames_1[_i];
|
|
225
|
+
return [4 /*yield*/, getMetric(qname, qrl, metricName, opt)];
|
|
226
|
+
case 3:
|
|
227
|
+
result = _b.sent();
|
|
228
|
+
results.push(result);
|
|
229
|
+
debug('getMetric result', result);
|
|
230
|
+
apiCalls.CloudWatch++;
|
|
231
|
+
// Recalculate idle
|
|
232
|
+
idle = result[metricName] === 0;
|
|
233
|
+
if (!idle)
|
|
234
|
+
return [3 /*break*/, 5]; // and stop checking metrics if we find evidence of activity
|
|
235
|
+
_b.label = 4;
|
|
236
|
+
case 4:
|
|
237
|
+
_i++;
|
|
238
|
+
return [3 /*break*/, 2];
|
|
239
|
+
case 5:
|
|
240
|
+
stats = Object.assign.apply(Object, __spreadArray([{
|
|
241
|
+
queue: qname.slice(opt.prefix.length),
|
|
242
|
+
cheap: cheapResult,
|
|
243
|
+
apiCalls: apiCalls,
|
|
244
|
+
idle: idle
|
|
245
|
+
}], results // merge in results from CloudWatch
|
|
246
|
+
, false));
|
|
247
|
+
debug('checkIdle stats', stats);
|
|
248
|
+
return [2 /*return*/, stats];
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
exports.checkIdle = checkIdle;
|
|
254
|
+
/**
|
|
255
|
+
* Just deletes a queue.
|
|
256
|
+
*/
|
|
257
|
+
function deleteQueue(qname, qrl, opt) {
|
|
258
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
259
|
+
var cmd, result;
|
|
260
|
+
return __generator(this, function (_a) {
|
|
261
|
+
switch (_a.label) {
|
|
262
|
+
case 0:
|
|
263
|
+
cmd = new client_sqs_1.DeleteQueueCommand({ QueueUrl: qrl });
|
|
264
|
+
return [4 /*yield*/, (0, sqs_js_1.getSQSClient)().send(cmd)];
|
|
265
|
+
case 1:
|
|
266
|
+
result = _a.sent();
|
|
267
|
+
debug(result);
|
|
268
|
+
if (opt.verbose)
|
|
269
|
+
console.error(chalk_1.default.blue('Deleted ') + qname.slice(opt.prefix.length));
|
|
270
|
+
return [2 /*return*/, {
|
|
271
|
+
deleted: true,
|
|
272
|
+
apiCalls: { SQS: 1, CloudWatch: 0 }
|
|
273
|
+
}];
|
|
274
|
+
}
|
|
275
|
+
});
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
exports.deleteQueue = deleteQueue;
|
|
279
|
+
/**
|
|
280
|
+
* Processes a single queue, checking for idle, deleting if applicable.
|
|
281
|
+
*/
|
|
282
|
+
function processQueue(qname, qrl, opt) {
|
|
283
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
284
|
+
var result, deleteResult, resultIncludingDelete;
|
|
285
|
+
return __generator(this, function (_a) {
|
|
286
|
+
switch (_a.label) {
|
|
287
|
+
case 0: return [4 /*yield*/, checkIdle(qname, qrl, opt)];
|
|
288
|
+
case 1:
|
|
289
|
+
result = _a.sent();
|
|
290
|
+
debug(qname, result);
|
|
291
|
+
// Queue is active
|
|
292
|
+
if (!result.idle) {
|
|
293
|
+
// Notify and return
|
|
294
|
+
if (opt.verbose)
|
|
295
|
+
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.'));
|
|
296
|
+
return [2 /*return*/, result];
|
|
297
|
+
}
|
|
298
|
+
// Queue is idle
|
|
299
|
+
if (opt.verbose)
|
|
300
|
+
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.'));
|
|
301
|
+
if (!opt.delete) return [3 /*break*/, 3];
|
|
302
|
+
return [4 /*yield*/, deleteQueue(qname, qrl, opt)];
|
|
303
|
+
case 2:
|
|
304
|
+
deleteResult = _a.sent();
|
|
305
|
+
resultIncludingDelete = Object.assign(result, {
|
|
306
|
+
deleted: deleteResult.deleted,
|
|
307
|
+
apiCalls: {
|
|
308
|
+
SQS: result.apiCalls.SQS + deleteResult.apiCalls.SQS,
|
|
309
|
+
CloudWatch: result.apiCalls.CloudWatch + deleteResult.apiCalls.CloudWatch
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
return [2 /*return*/, resultIncludingDelete];
|
|
313
|
+
case 3: return [2 /*return*/];
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
exports.processQueue = processQueue;
|
|
319
|
+
/**
|
|
320
|
+
* Processes a queue and its fail queue, treating them as a unit.
|
|
321
|
+
*/
|
|
322
|
+
function processQueuePair(qname, qrl, opt) {
|
|
323
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
324
|
+
var isFifo, normalizeOptions, fqname, fqrl, result, active, fresult, idleCheckResult, factive, _a, dresult, dfresult, e_1, deleteResult, resultIncludingDelete;
|
|
325
|
+
return __generator(this, function (_b) {
|
|
326
|
+
switch (_b.label) {
|
|
327
|
+
case 0:
|
|
328
|
+
isFifo = qname.endsWith('.fifo');
|
|
329
|
+
normalizeOptions = Object.assign({}, opt, { fifo: isFifo });
|
|
330
|
+
fqname = (0, qrlCache_js_1.normalizeFailQueueName)(qname, normalizeOptions);
|
|
331
|
+
fqrl = (0, qrlCache_js_1.normalizeFailQueueName)(qrl, normalizeOptions);
|
|
332
|
+
return [4 /*yield*/, checkIdle(qname, qrl, opt)];
|
|
333
|
+
case 1:
|
|
334
|
+
result = _b.sent();
|
|
335
|
+
debug('result', result);
|
|
336
|
+
active = !result.idle;
|
|
337
|
+
if (active) {
|
|
338
|
+
if (opt.verbose)
|
|
339
|
+
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.'));
|
|
340
|
+
return [2 /*return*/, result];
|
|
341
|
+
}
|
|
342
|
+
// Queue is idle
|
|
343
|
+
if (opt.verbose)
|
|
344
|
+
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.'));
|
|
345
|
+
_b.label = 2;
|
|
346
|
+
case 2:
|
|
347
|
+
_b.trys.push([2, 5, , 7]);
|
|
348
|
+
return [4 /*yield*/, checkIdle(fqname, fqrl, opt)];
|
|
349
|
+
case 3:
|
|
350
|
+
fresult = _b.sent();
|
|
351
|
+
debug('fresult', fresult);
|
|
352
|
+
idleCheckResult = Object.assign(result, { idle: result.idle && fresult.idle, failq: fresult }, {
|
|
353
|
+
apiCalls: {
|
|
354
|
+
SQS: result.apiCalls.SQS + fresult.apiCalls.SQS,
|
|
355
|
+
CloudWatch: result.apiCalls.CloudWatch + fresult.apiCalls.CloudWatch
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
factive = !fresult.idle;
|
|
359
|
+
if (factive) {
|
|
360
|
+
if (opt.verbose)
|
|
361
|
+
console.error(chalk_1.default.blue('Queue ') + fqname.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.'));
|
|
362
|
+
return [2 /*return*/, idleCheckResult];
|
|
363
|
+
}
|
|
364
|
+
// Queue is idle
|
|
365
|
+
if (opt.verbose)
|
|
366
|
+
console.error(chalk_1.default.blue('Queue ') + fqname.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.'));
|
|
367
|
+
// Trigger a delete if the user wants it
|
|
368
|
+
if (!opt.delete)
|
|
369
|
+
return [2 /*return*/, idleCheckResult];
|
|
370
|
+
return [4 /*yield*/, Promise.all([
|
|
371
|
+
deleteQueue(qname, qrl, opt),
|
|
372
|
+
deleteQueue(fqname, fqrl, opt)
|
|
373
|
+
])];
|
|
374
|
+
case 4:
|
|
375
|
+
_a = _b.sent(), dresult = _a[0], dfresult = _a[1];
|
|
376
|
+
return [2 /*return*/, Object.assign(idleCheckResult, {
|
|
377
|
+
apiCalls: {
|
|
378
|
+
// Sum the SQS calls across all four
|
|
379
|
+
SQS: [result, fresult, dresult, dfresult]
|
|
380
|
+
.map(function (r) { return r.apiCalls.SQS; })
|
|
381
|
+
.reduce(function (a, b) { return a + b; }, 0),
|
|
382
|
+
// Sum the CloudWatch calls across all four
|
|
383
|
+
CloudWatch: [result, fresult, dresult, dfresult]
|
|
384
|
+
.map(function (r) { return r.apiCalls.CloudWatch; })
|
|
385
|
+
.reduce(function (a, b) { return a + b; }, 0)
|
|
386
|
+
}
|
|
387
|
+
})];
|
|
388
|
+
case 5:
|
|
389
|
+
e_1 = _b.sent();
|
|
390
|
+
// Handle the case where the fail queue has been deleted or was never
|
|
391
|
+
// created for some reason
|
|
392
|
+
if (!(e_1 instanceof client_sqs_1.QueueDoesNotExist))
|
|
393
|
+
throw e_1;
|
|
394
|
+
// Fail queue doesn't exist if we get here
|
|
395
|
+
if (opt.verbose)
|
|
396
|
+
console.error(chalk_1.default.blue('Queue ') + fqname.slice(opt.prefix.length) + chalk_1.default.blue(' does not exist.'));
|
|
397
|
+
// Handle delete
|
|
398
|
+
if (!opt.delete)
|
|
399
|
+
return [2 /*return*/, result];
|
|
400
|
+
return [4 /*yield*/, deleteQueue(qname, qrl, opt)];
|
|
401
|
+
case 6:
|
|
402
|
+
deleteResult = _b.sent();
|
|
403
|
+
resultIncludingDelete = Object.assign(result, {
|
|
404
|
+
deleted: deleteResult.deleted,
|
|
405
|
+
apiCalls: {
|
|
406
|
+
SQS: result.apiCalls.SQS + deleteResult.apiCalls.SQS,
|
|
407
|
+
CloudWatch: result.apiCalls.CloudWatch + deleteResult.apiCalls.CloudWatch
|
|
408
|
+
}
|
|
409
|
+
});
|
|
410
|
+
return [2 /*return*/, resultIncludingDelete];
|
|
411
|
+
case 7: return [2 /*return*/];
|
|
412
|
+
}
|
|
413
|
+
});
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
exports.processQueuePair = processQueuePair;
|
|
417
|
+
//
|
|
418
|
+
// Resolve queues for listening loop listen
|
|
419
|
+
//
|
|
420
|
+
function idleQueues(queues, options) {
|
|
421
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
422
|
+
var opt, qnames, entries, filteredEntries;
|
|
423
|
+
return __generator(this, function (_a) {
|
|
424
|
+
switch (_a.label) {
|
|
425
|
+
case 0:
|
|
426
|
+
opt = (0, defaults_js_1.getOptionsWithDefaults)(options);
|
|
427
|
+
if (opt.verbose)
|
|
428
|
+
console.error(chalk_1.default.blue('Resolving queues: ') + queues.join(' '));
|
|
429
|
+
qnames = queues.map(function (queue) { return opt.prefix + queue; });
|
|
430
|
+
return [4 /*yield*/, (0, qrlCache_js_1.getQnameUrlPairs)(qnames, opt)];
|
|
431
|
+
case 1:
|
|
432
|
+
entries = _a.sent();
|
|
433
|
+
debug('getQnameUrlPairs.then');
|
|
434
|
+
if (opt.verbose) {
|
|
435
|
+
console.error(chalk_1.default.blue(' done'));
|
|
436
|
+
console.error();
|
|
437
|
+
}
|
|
438
|
+
filteredEntries = entries.filter(function (entry) {
|
|
439
|
+
var suf = opt.failSuffix;
|
|
440
|
+
var sufFifo = opt.failSuffix + qrlCache_js_1.fifoSuffix;
|
|
441
|
+
var isFail = entry.qname.endsWith(suf);
|
|
442
|
+
var isFifoFail = entry.qname.endsWith(sufFifo);
|
|
443
|
+
return opt.includeFailed ? true : (!isFail && !isFifoFail);
|
|
444
|
+
});
|
|
445
|
+
// But only if we have queues to remove
|
|
446
|
+
if (filteredEntries.length) {
|
|
447
|
+
if (opt.verbose) {
|
|
448
|
+
console.error(chalk_1.default.blue('Checking queues (in this order):'));
|
|
449
|
+
console.error(filteredEntries.map(function (e) {
|
|
450
|
+
return ' ' + e.qname.slice(opt.prefix.length) + chalk_1.default.blue(' - ' + e.qrl);
|
|
451
|
+
}).join('\n'));
|
|
452
|
+
console.error();
|
|
453
|
+
}
|
|
454
|
+
// Check each queue in parallel
|
|
455
|
+
if (opt.unpair)
|
|
456
|
+
return [2 /*return*/, Promise.all(filteredEntries.map(function (e) { return processQueue(e.qname, e.qrl, opt); }))];
|
|
457
|
+
return [2 /*return*/, Promise.all(filteredEntries.map(function (e) { return processQueuePair(e.qname, e.qrl, opt); }))];
|
|
458
|
+
}
|
|
459
|
+
// Otherwise, let caller know
|
|
460
|
+
return [2 /*return*/, 'noQueues'];
|
|
461
|
+
}
|
|
462
|
+
});
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
exports.idleQueues = idleQueues;
|
|
466
|
+
debug('loaded');
|