qdone 1.7.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.
@@ -0,0 +1,483 @@
1
+ "use strict";
2
+ /**
3
+ * Consumer implementation.
4
+ */
5
+ var __extends = (this && this.__extends) || (function () {
6
+ var extendStatics = function (d, b) {
7
+ extendStatics = Object.setPrototypeOf ||
8
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
9
+ function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
10
+ return extendStatics(d, b);
11
+ };
12
+ return function (d, b) {
13
+ if (typeof b !== "function" && b !== null)
14
+ throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
15
+ extendStatics(d, b);
16
+ function __() { this.constructor = d; }
17
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
18
+ };
19
+ })();
20
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
21
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
22
+ return new (P || (P = Promise))(function (resolve, reject) {
23
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
24
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
25
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
26
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
27
+ });
28
+ };
29
+ var __generator = (this && this.__generator) || function (thisArg, body) {
30
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
31
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
32
+ function verb(n) { return function (v) { return step([n, v]); }; }
33
+ function step(op) {
34
+ if (f) throw new TypeError("Generator is already executing.");
35
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
36
+ 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;
37
+ if (y = 0, t) op = [op[0] & 2, t.value];
38
+ switch (op[0]) {
39
+ case 0: case 1: t = op; break;
40
+ case 4: _.label++; return { value: op[1], done: false };
41
+ case 5: _.label++; y = op[1]; op = [0]; continue;
42
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
43
+ default:
44
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
45
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
46
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
47
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
48
+ if (t[2]) _.ops.pop();
49
+ _.trys.pop(); continue;
50
+ }
51
+ op = body.call(thisArg, _);
52
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
53
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
54
+ }
55
+ };
56
+ var __importDefault = (this && this.__importDefault) || function (mod) {
57
+ return (mod && mod.__esModule) ? mod : { "default": mod };
58
+ };
59
+ Object.defineProperty(exports, "__esModule", { value: true });
60
+ exports.processMessages = exports.resolveQueues = exports.pollSingleQueue = exports.processMessage = exports.requestShutdown = exports.DoNotProcess = void 0;
61
+ var client_sqs_1 = require("@aws-sdk/client-sqs");
62
+ var chalk_1 = __importDefault(require("chalk"));
63
+ var debug_1 = __importDefault(require("debug"));
64
+ var qrlCache_js_1 = require("./qrlCache.js");
65
+ var idleQueues_js_1 = require("./idleQueues.js");
66
+ var defaults_js_1 = require("./defaults.js");
67
+ var sqs_js_1 = require("./sqs.js");
68
+ //
69
+ // Throwing an instance of this Error allows the processMessages callback to
70
+ // refuse a message which then gets immediately returned to the queue.
71
+ //
72
+ // This has the side effect of throtting the queue since it stops polling on
73
+ // the queue until the next queue resolution in processMessages.
74
+ //
75
+ // This is useful for implementing schedulers on top of qdone, for example, to
76
+ // look at the queue name and decide whether to take on a new message.
77
+ //
78
+ var DoNotProcess = /** @class */ (function (_super) {
79
+ __extends(DoNotProcess, _super);
80
+ function DoNotProcess() {
81
+ return _super !== null && _super.apply(this, arguments) || this;
82
+ }
83
+ return DoNotProcess;
84
+ }(Error));
85
+ exports.DoNotProcess = DoNotProcess;
86
+ var debug = (0, debug_1.default)('qdone:worker');
87
+ // Global flag for shutdown request
88
+ var shutdownRequested = false;
89
+ var shutdownCallbacks = [];
90
+ function requestShutdown() {
91
+ shutdownRequested = true;
92
+ for (var _i = 0, shutdownCallbacks_1 = shutdownCallbacks; _i < shutdownCallbacks_1.length; _i++) {
93
+ var callback = shutdownCallbacks_1[_i];
94
+ try {
95
+ callback();
96
+ }
97
+ catch (e) { }
98
+ }
99
+ }
100
+ exports.requestShutdown = requestShutdown;
101
+ function processMessage(message, callback, qname, qrl, opt) {
102
+ return __awaiter(this, void 0, void 0, function () {
103
+ function extendTimeout() {
104
+ return __awaiter(this, void 0, void 0, function () {
105
+ var maxJobRun, jobRunTime, result, err_2;
106
+ return __generator(this, function (_a) {
107
+ switch (_a.label) {
108
+ case 0:
109
+ debug('extendTimeout');
110
+ maxJobRun = 12 * 60 * 60;
111
+ jobRunTime = ((new Date()) - jobStart) / 1000;
112
+ // Double every time, up to max
113
+ visibilityTimeout = Math.min(visibilityTimeout * 2, maxJobRun - jobRunTime, opt.killAfter - jobRunTime);
114
+ if (opt.verbose) {
115
+ console.error(chalk_1.default.blue(' Ran for ') + jobRunTime +
116
+ chalk_1.default.blue(' seconds, requesting another ') + visibilityTimeout +
117
+ chalk_1.default.blue(' seconds'));
118
+ }
119
+ _a.label = 1;
120
+ case 1:
121
+ _a.trys.push([1, 3, , 4]);
122
+ return [4 /*yield*/, (0, sqs_js_1.getSQSClient)().send(new client_sqs_1.ChangeMessageVisibilityCommand({
123
+ QueueUrl: qrl,
124
+ ReceiptHandle: message.ReceiptHandle,
125
+ VisibilityTimeout: visibilityTimeout
126
+ }))];
127
+ case 2:
128
+ result = _a.sent();
129
+ debug('ChangeMessageVisibility returned', result);
130
+ if (jobRunTime + visibilityTimeout >= maxJobRun ||
131
+ jobRunTime + visibilityTimeout >= opt.killAfter) {
132
+ if (opt.verbose)
133
+ console.error(chalk_1.default.yellow(' warning: this is our last time extension'));
134
+ }
135
+ else {
136
+ // Extend when we get 50% of the way to timeout
137
+ timeoutExtender = setTimeout(extendTimeout, visibilityTimeout * 1000 * 0.5);
138
+ }
139
+ return [3 /*break*/, 4];
140
+ case 3:
141
+ err_2 = _a.sent();
142
+ debug('ChangeMessageVisibility threw', err_2);
143
+ // Rejection means we're ouuta time, whatever, let the job die
144
+ if (opt.verbose) {
145
+ console.error(chalk_1.default.red(' failed to extend job: ') + err_2);
146
+ }
147
+ else if (!opt.disableLog) {
148
+ // Production error logging
149
+ console.log(JSON.stringify({
150
+ event: 'MESSAGE_PROCESSING_FAILED',
151
+ reason: 'ran longer than --kill-after',
152
+ timestamp: new Date(),
153
+ messageId: message.MessageId,
154
+ payload: payload,
155
+ errorMessage: err_2.toString().split('\n').slice(1).join('\n').trim() || undefined,
156
+ err: err_2
157
+ }));
158
+ }
159
+ return [3 /*break*/, 4];
160
+ case 4: return [2 /*return*/];
161
+ }
162
+ });
163
+ });
164
+ }
165
+ var payload, jobStart, visibilityTimeout, timeoutExtender, queue, result, err_1, result;
166
+ return __generator(this, function (_a) {
167
+ switch (_a.label) {
168
+ case 0:
169
+ debug('processMessage', message, qname, qrl);
170
+ payload = JSON.parse(message.Body);
171
+ if (opt.verbose) {
172
+ console.error(chalk_1.default.blue(' Processing payload:'), payload);
173
+ }
174
+ else if (!opt.disableLog) {
175
+ console.log(JSON.stringify({
176
+ event: 'MESSAGE_PROCESSING_START',
177
+ timestamp: new Date(),
178
+ messageId: message.MessageId,
179
+ payload: payload
180
+ }));
181
+ }
182
+ jobStart = new Date();
183
+ visibilityTimeout = 30 // this should be the queue timeout
184
+ ;
185
+ // Extend when we get 50% of the way to timeout
186
+ timeoutExtender = setTimeout(extendTimeout, visibilityTimeout * 1000 * 0.5);
187
+ debug('timeout', visibilityTimeout * 1000 * 0.5);
188
+ _a.label = 1;
189
+ case 1:
190
+ _a.trys.push([1, 4, , 7]);
191
+ queue = qname.slice(opt.prefix.length);
192
+ return [4 /*yield*/, callback(queue, payload)];
193
+ case 2:
194
+ result = _a.sent();
195
+ debug('processMessage callback finished', { payload: payload, result: result });
196
+ clearTimeout(timeoutExtender);
197
+ if (opt.verbose) {
198
+ console.error(chalk_1.default.green(' SUCCESS'));
199
+ console.error(chalk_1.default.blue(' cleaning up (removing message) ...'));
200
+ }
201
+ return [4 /*yield*/, (0, sqs_js_1.getSQSClient)().send(new client_sqs_1.DeleteMessageCommand({
202
+ QueueUrl: qrl,
203
+ ReceiptHandle: message.ReceiptHandle
204
+ }))];
205
+ case 3:
206
+ _a.sent();
207
+ if (opt.verbose) {
208
+ console.error(chalk_1.default.blue(' done'));
209
+ console.error();
210
+ }
211
+ else if (!opt.disableLog) {
212
+ console.log(JSON.stringify({
213
+ event: 'MESSAGE_PROCESSING_COMPLETE',
214
+ timestamp: new Date(),
215
+ messageId: message.MessageId,
216
+ payload: payload
217
+ }));
218
+ }
219
+ return [2 /*return*/, { noJobs: 0, jobsSucceeded: 1, jobsFailed: 0 }];
220
+ case 4:
221
+ err_1 = _a.sent();
222
+ debug('exec.catch');
223
+ clearTimeout(timeoutExtender);
224
+ if (!(err_1 instanceof DoNotProcess)) return [3 /*break*/, 6];
225
+ if (opt.verbose) {
226
+ console.error(chalk_1.default.blue(' callback ') + chalk_1.default.yellow('REFUSED'));
227
+ console.error(chalk_1.default.blue(' cleaning up (removing message) ...'));
228
+ }
229
+ return [4 /*yield*/, (0, sqs_js_1.getSQSClient)().send(new client_sqs_1.ChangeMessageVisibilityCommand({
230
+ QueueUrl: qrl,
231
+ ReceiptHandle: message.ReceiptHandle,
232
+ VisibilityTimeout: 0
233
+ }))];
234
+ case 5:
235
+ result = _a.sent();
236
+ debug('ChangeMessageVisibility returned', result);
237
+ return [2 /*return*/, { noJobs: 1, jobsSucceeded: 0, jobsFailed: 0 }];
238
+ case 6:
239
+ // Fail path for job execution
240
+ if (opt.verbose) {
241
+ console.error(chalk_1.default.red(' FAILED'));
242
+ console.error(chalk_1.default.blue(' error : ') + err_1);
243
+ }
244
+ else if (!opt.disableLog) {
245
+ // Production error logging
246
+ console.log(JSON.stringify({
247
+ event: 'MESSAGE_PROCESSING_FAILED',
248
+ reason: 'exception thrown',
249
+ timestamp: new Date(),
250
+ messageId: message.MessageId,
251
+ payload: payload,
252
+ errorMessage: err_1.toString().split('\n').slice(1).join('\n').trim() || undefined,
253
+ err: err_1
254
+ }));
255
+ }
256
+ return [2 /*return*/, { noJobs: 0, jobsSucceeded: 0, jobsFailed: 1 }];
257
+ case 7: return [2 /*return*/];
258
+ }
259
+ });
260
+ });
261
+ }
262
+ exports.processMessage = processMessage;
263
+ //
264
+ // Pull work off of a single queue
265
+ //
266
+ function pollSingleQueue(qname, qrl, callback, opt) {
267
+ return __awaiter(this, void 0, void 0, function () {
268
+ var params, response, message;
269
+ return __generator(this, function (_a) {
270
+ switch (_a.label) {
271
+ case 0:
272
+ debug('pollSingleQueue', { qname: qname, qrl: qrl, callback: callback, opt: opt });
273
+ params = {
274
+ AttributeNames: ['All'],
275
+ MaxNumberOfMessages: 1,
276
+ MessageAttributeNames: ['All'],
277
+ QueueUrl: qrl,
278
+ VisibilityTimeout: 30,
279
+ WaitTimeSeconds: opt.waitTime
280
+ };
281
+ return [4 /*yield*/, (0, sqs_js_1.getSQSClient)().send(new client_sqs_1.ReceiveMessageCommand(params))];
282
+ case 1:
283
+ response = _a.sent();
284
+ debug('ReceiveMessage response', response);
285
+ if (shutdownRequested)
286
+ return [2 /*return*/, { noJobs: 0, jobsSucceeded: 0, jobsFailed: 0 }];
287
+ if (response.Messages) {
288
+ message = response.Messages[0];
289
+ if (opt.verbose)
290
+ console.error(chalk_1.default.blue(' Found message ' + message.MessageId));
291
+ return [2 /*return*/, processMessage(message, callback, qname, qrl, opt)];
292
+ }
293
+ else {
294
+ return [2 /*return*/, { noJobs: 1, jobsSucceeded: 0, jobsFailed: 0 }];
295
+ }
296
+ return [2 /*return*/];
297
+ }
298
+ });
299
+ });
300
+ }
301
+ exports.pollSingleQueue = pollSingleQueue;
302
+ //
303
+ // Resolve a set of queues
304
+ //
305
+ function resolveQueues(queues, opt) {
306
+ return __awaiter(this, void 0, void 0, function () {
307
+ var qnames, pairs, activePairs, selectedPairs;
308
+ var _this = this;
309
+ return __generator(this, function (_a) {
310
+ switch (_a.label) {
311
+ case 0:
312
+ // Start processing
313
+ if (opt.verbose)
314
+ console.error(chalk_1.default.blue('Resolving queues: ') + queues.join(' '));
315
+ qnames = queues.map(function (queue) { return (0, qrlCache_js_1.normalizeQueueName)(queue, opt); });
316
+ return [4 /*yield*/, (0, qrlCache_js_1.getQnameUrlPairs)(qnames, opt)
317
+ // Figure out which pairs are active
318
+ ];
319
+ case 1:
320
+ pairs = _a.sent();
321
+ activePairs = [];
322
+ if (!opt.activeOnly) return [3 /*break*/, 3];
323
+ debug({ pairsBeforeCheck: pairs });
324
+ return [4 /*yield*/, Promise.all(pairs.map(function (pair) { return __awaiter(_this, void 0, void 0, function () {
325
+ var idle;
326
+ return __generator(this, function (_a) {
327
+ switch (_a.label) {
328
+ case 0: return [4 /*yield*/, (0, idleQueues_js_1.cheapIdleCheck)(pair.qname, pair.qrl, opt)];
329
+ case 1:
330
+ idle = (_a.sent()).idle;
331
+ if (!idle)
332
+ activePairs.push(pair);
333
+ return [2 /*return*/];
334
+ }
335
+ });
336
+ }); }))];
337
+ case 2:
338
+ _a.sent();
339
+ _a.label = 3;
340
+ case 3:
341
+ // Finished resolving
342
+ debug('getQnameUrlPairs.then');
343
+ if (opt.verbose) {
344
+ console.error(chalk_1.default.blue(' done'));
345
+ console.error();
346
+ }
347
+ selectedPairs = (opt.activeOnly ? activePairs : pairs)
348
+ .filter(function (_a) {
349
+ var qname = _a.qname;
350
+ var suf = opt.failSuffix + (opt.fifo ? '.fifo' : '');
351
+ var isFailQueue = qname.slice(-suf.length) === suf;
352
+ var shouldInclude = opt.includeFailed ? true : !isFailQueue;
353
+ return shouldInclude;
354
+ });
355
+ return [2 /*return*/, selectedPairs];
356
+ }
357
+ });
358
+ });
359
+ }
360
+ exports.resolveQueues = resolveQueues;
361
+ //
362
+ // Consumer
363
+ //
364
+ function processMessages(queues, callback, options) {
365
+ return __awaiter(this, void 0, void 0, function () {
366
+ // Callback to help facilitate better UX at shutdown
367
+ function shutdownCallback() {
368
+ if (opt.verbose) {
369
+ debug({ activeLoops: activeLoops });
370
+ var activeQueues = Object.keys(activeLoops).filter(function (q) { return activeLoops[q]; }).map(function (q) { return q.slice(opt.prefix.length); });
371
+ if (activeQueues.length) {
372
+ console.error(chalk_1.default.blue('Waiting for work to finish on the following queues: ') + activeQueues.join(chalk_1.default.blue(', ')));
373
+ }
374
+ clearTimeout(delayTimeout);
375
+ }
376
+ }
377
+ // Listen to a queue until it is out of messages
378
+ function listenLoop(qname, qrl) {
379
+ return __awaiter(this, void 0, void 0, function () {
380
+ var _a, noJobs, jobsSucceeded, jobsFailed, err_3;
381
+ return __generator(this, function (_b) {
382
+ switch (_b.label) {
383
+ case 0:
384
+ _b.trys.push([0, 2, 3, 4]);
385
+ if (shutdownRequested)
386
+ return [2 /*return*/];
387
+ if (opt.verbose) {
388
+ console.error(chalk_1.default.blue('Looking for work on ') +
389
+ qname.slice(opt.prefix.length) +
390
+ chalk_1.default.blue(' (' + qrl + ')'));
391
+ }
392
+ return [4 /*yield*/, pollSingleQueue(qname, qrl, callback, opt)];
393
+ case 1:
394
+ _a = _b.sent(), noJobs = _a.noJobs, jobsSucceeded = _a.jobsSucceeded, jobsFailed = _a.jobsFailed;
395
+ stats.noJobs += noJobs;
396
+ stats.jobsFailed += jobsFailed;
397
+ stats.jobsSucceeded += jobsSucceeded;
398
+ // No work? return to outer loop
399
+ if (noJobs)
400
+ return [2 /*return*/];
401
+ // Otherwise keep going
402
+ return [2 /*return*/, listenLoop(qname, qrl)];
403
+ case 2:
404
+ err_3 = _b.sent();
405
+ // TODO: Sentry
406
+ console.error(chalk_1.default.red(' ERROR in listenLoop'));
407
+ console.error(chalk_1.default.blue(' error : ') + err_3);
408
+ return [3 /*break*/, 4];
409
+ case 3:
410
+ delete activeLoops[qname];
411
+ return [7 /*endfinally*/];
412
+ case 4: return [2 /*return*/];
413
+ }
414
+ });
415
+ });
416
+ }
417
+ var opt, stats, activeLoops, delayTimeout, delay, start, selectedPairs, _i, selectedPairs_1, _a, qname, qrl, msSoFar, msUntilNextResolve;
418
+ return __generator(this, function (_b) {
419
+ switch (_b.label) {
420
+ case 0:
421
+ opt = (0, defaults_js_1.getOptionsWithDefaults)(options);
422
+ debug('processMessages', { queues: queues, callback: callback, options: options, opt: opt });
423
+ stats = { noJobs: 0, jobsSucceeded: 0, jobsFailed: 0 };
424
+ activeLoops = {};
425
+ delay = function (ms) { return new Promise(function (resolve) {
426
+ delayTimeout = setTimeout(resolve, ms);
427
+ }); };
428
+ shutdownCallbacks.push(shutdownCallback);
429
+ _b.label = 1;
430
+ case 1:
431
+ if (!!shutdownRequested) return [3 /*break*/, 5];
432
+ start = new Date();
433
+ return [4 /*yield*/, resolveQueues(queues, opt)];
434
+ case 2:
435
+ selectedPairs = _b.sent();
436
+ if (shutdownRequested)
437
+ return [3 /*break*/, 5];
438
+ // But only if we have queues to listen on
439
+ if (selectedPairs.length) {
440
+ // Randomize order
441
+ selectedPairs.sort(function () { return 0.5 - Math.random(); });
442
+ if (opt.verbose) {
443
+ console.error(chalk_1.default.blue('Listening to queues (in this order):'));
444
+ console.error(selectedPairs.map(function (_a) {
445
+ var qname = _a.qname, qrl = _a.qrl;
446
+ return ' ' + qname.slice(opt.prefix.length) + chalk_1.default.blue(' - ' + qrl);
447
+ }).join('\n'));
448
+ console.error();
449
+ }
450
+ // Launch listen loop for each queue
451
+ for (_i = 0, selectedPairs_1 = selectedPairs; _i < selectedPairs_1.length; _i++) {
452
+ _a = selectedPairs_1[_i], qname = _a.qname, qrl = _a.qrl;
453
+ if (!activeLoops[qname])
454
+ activeLoops[qname] = listenLoop(qname, qrl);
455
+ }
456
+ }
457
+ if (!!shutdownRequested) return [3 /*break*/, 4];
458
+ msSoFar = Math.max(0, new Date() - start);
459
+ msUntilNextResolve = Math.max(0, opt.waitTime * 1000 - msSoFar);
460
+ debug({ msSoFar: msSoFar, msUntilNextResolve: msUntilNextResolve });
461
+ if (!msUntilNextResolve) return [3 /*break*/, 4];
462
+ if (opt.verbose)
463
+ console.error(chalk_1.default.blue('Will resolve queues again in ' + Math.round(msUntilNextResolve / 1000) + ' seconds'));
464
+ return [4 /*yield*/, delay(msUntilNextResolve)];
465
+ case 3:
466
+ _b.sent();
467
+ _b.label = 4;
468
+ case 4: return [3 /*break*/, 1];
469
+ case 5:
470
+ // Wait on all work to finish
471
+ // shutdownCallback()
472
+ return [4 /*yield*/, Promise.all(Object.values(activeLoops))];
473
+ case 6:
474
+ // Wait on all work to finish
475
+ // shutdownCallback()
476
+ _b.sent();
477
+ return [2 /*return*/];
478
+ }
479
+ });
480
+ });
481
+ }
482
+ exports.processMessages = processMessages;
483
+ debug('loaded');
@@ -0,0 +1,107 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.setupVerbose = exports.setupAWS = exports.getOptionsWithDefaults = exports.defaults = void 0;
4
+ /**
5
+ * Default options for qdone. Accepts a command line options object and
6
+ * returns nicely-named options.
7
+ */
8
+ var uuid_1 = require("uuid");
9
+ exports.defaults = Object.freeze({
10
+ // Shared
11
+ prefix: 'qdone_',
12
+ failSuffix: '_failed',
13
+ region: 'us-east-1',
14
+ quiet: false,
15
+ verbose: false,
16
+ cache: false,
17
+ cacheUri: undefined,
18
+ cachePrefix: 'qdone:',
19
+ cacheTtlSeconds: 10,
20
+ fifo: false,
21
+ disableLog: false,
22
+ includeFailed: false,
23
+ // Enqueue
24
+ groupId: (0, uuid_1.v1)(),
25
+ groupIdPerMessage: false,
26
+ deduplicationId: (0, uuid_1.v1)(),
27
+ messageRetentionPeriod: 1209600,
28
+ delay: 0,
29
+ dlq: false,
30
+ dlqSuffix: '_dead',
31
+ dlqAfter: 3,
32
+ // Worker
33
+ waitTime: 20,
34
+ killAfter: 30,
35
+ archive: false,
36
+ activeOnly: false,
37
+ // Idle Queues
38
+ idleFor: 60,
39
+ delete: false,
40
+ unpair: false
41
+ });
42
+ /**
43
+ * This function should be called by each exposed API entry point on the
44
+ * options passed in from the caller. It supports options named in camelCase
45
+ * and also in command-line-style returned by our parsers.
46
+ *
47
+ * By convention, we name the variable "options" if it comes from the user
48
+ * and "opt" if it has already passed through this function.
49
+ */
50
+ function getOptionsWithDefaults(options) {
51
+ // For API invocations don't force caller to supply default options
52
+ if (!options)
53
+ options = {};
54
+ // Activate DLQ if any option is set
55
+ var dlq = options.dlq || !!(options['dlq-suffix'] || options['dlq-after'] || options['dlq-name']);
56
+ var opt = {
57
+ // Shared
58
+ prefix: options.prefix === '' ? options.prefix : (options.prefix || exports.defaults.prefix),
59
+ failSuffix: options.failSuffix || options['fail-suffix'] || exports.defaults.failSuffix,
60
+ region: options.region || process.env.AWS_REGION || exports.defaults.region,
61
+ quiet: options.quiet || exports.defaults.quiet,
62
+ verbose: options.verbose || exports.defaults.verbose,
63
+ fifo: options.fifo || exports.defaults.fifo,
64
+ sentryDsn: options.sentryDsn || options['sentry-dsn'],
65
+ disableLog: options.disableLog || options['disable-log'] || exports.defaults.disableLog,
66
+ // Cache
67
+ cacheUri: options.cacheUri || options['cache-uri'] || exports.defaults.cacheUri,
68
+ cachePrefix: options.cachePrefix || options['cache-prefix'] || exports.defaults.cachePrefix,
69
+ cacheTtlSeconds: options.cacheTtlSeconds || options['cache-ttl-seconds'] || exports.defaults.cacheTtlSeconds,
70
+ // Enqueue
71
+ groupId: options.groupId || options['group-id'] || exports.defaults.groupId,
72
+ groupIdPerMessage: false,
73
+ deduplicationId: options.deduplicationId || options['deduplication-id'] || exports.defaults.deduplicationId,
74
+ messageRetentionPeriod: options.messageRetentionPeriod || options['message-retention-period'] || exports.defaults.messageRetentionPeriod,
75
+ delay: options.delay || exports.defaults.delay,
76
+ dlq: dlq || exports.defaults.dlq,
77
+ dlqSuffix: options.dlqSuffix || options['dlq-suffix'] || exports.defaults.dlqSuffix,
78
+ dlqAfter: options.dlqAfter || options['dlq-after'] || exports.defaults.dlqAfter,
79
+ tags: options.tags || undefined,
80
+ // Worker
81
+ waitTime: options.waitTime || options['wait-time'] || exports.defaults.waitTime,
82
+ killAfter: options.killAfter || options['kill-after'] || exports.defaults.killAfter,
83
+ archive: options.archive || exports.defaults.archive,
84
+ activeOnly: options.activeOnly || options['active-only'] || exports.defaults.activeOnly,
85
+ includeFailed: options.includeFailed || options['include-failed'] || exports.defaults.includeFailed,
86
+ // Idle Queues
87
+ idleFor: options.idleFor || options['idle-for'] || exports.defaults.idleFor,
88
+ delete: options.delete || exports.defaults.delete,
89
+ unpair: options.delete || exports.defaults.unpair
90
+ };
91
+ process.env.AWS_REGION = opt.region;
92
+ // TODO: validate options
93
+ return opt;
94
+ }
95
+ exports.getOptionsWithDefaults = getOptionsWithDefaults;
96
+ function setupAWS(options) {
97
+ var opt = getOptionsWithDefaults(options);
98
+ process.env.AWS_REGION = opt.region;
99
+ }
100
+ exports.setupAWS = setupAWS;
101
+ function setupVerbose(options) {
102
+ var verbose = options.verbose || (process.stderr.isTTY && !options.quiet);
103
+ var quiet = options.quiet || (!process.stderr.isTTY && !options.verbose);
104
+ options.verbose = verbose;
105
+ options.quiet = quiet;
106
+ }
107
+ exports.setupVerbose = setupVerbose;