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,498 @@
1
+ "use strict";
2
+ // const Q = require('q')
3
+ // const debug = require('debug')('qdone:enqueue')
4
+ // const chalk = require('chalk')
5
+ // const uuid = require('uuid')
6
+ // const qrlCache = require('./qrlCache')
7
+ // const AWS = require('aws-sdk')
8
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
9
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
10
+ return new (P || (P = Promise))(function (resolve, reject) {
11
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
12
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
13
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
14
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
15
+ });
16
+ };
17
+ var __generator = (this && this.__generator) || function (thisArg, body) {
18
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
19
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
20
+ function verb(n) { return function (v) { return step([n, v]); }; }
21
+ function step(op) {
22
+ if (f) throw new TypeError("Generator is already executing.");
23
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
24
+ 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;
25
+ if (y = 0, t) op = [op[0] & 2, t.value];
26
+ switch (op[0]) {
27
+ case 0: case 1: t = op; break;
28
+ case 4: _.label++; return { value: op[1], done: false };
29
+ case 5: _.label++; y = op[1]; op = [0]; continue;
30
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
31
+ default:
32
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
33
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
34
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
35
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
36
+ if (t[2]) _.ops.pop();
37
+ _.trys.pop(); continue;
38
+ }
39
+ op = body.call(thisArg, _);
40
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
41
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
42
+ }
43
+ };
44
+ var __importDefault = (this && this.__importDefault) || function (mod) {
45
+ return (mod && mod.__esModule) ? mod : { "default": mod };
46
+ };
47
+ Object.defineProperty(exports, "__esModule", { value: true });
48
+ exports.enqueueBatch = exports.enqueue = exports.addMessage = exports.flushMessages = exports.sendMessageBatch = exports.sendMessage = exports.formatMessage = exports.getQueueAttributes = exports.getOrCreateQueue = exports.getOrCreateFailQueue = exports.getOrCreateDLQ = void 0;
49
+ var uuid_1 = require("uuid");
50
+ var chalk_1 = __importDefault(require("chalk"));
51
+ var debug_1 = __importDefault(require("debug"));
52
+ var client_sqs_1 = require("@aws-sdk/client-sqs");
53
+ var qrlCache_js_1 = require("./qrlCache.js");
54
+ var sqs_js_1 = require("./sqs.js");
55
+ var defaults_js_1 = require("./defaults.js");
56
+ var debug = (0, debug_1.default)('qdone:enqueue');
57
+ function getOrCreateDLQ(queue, opt) {
58
+ return __awaiter(this, void 0, void 0, function () {
59
+ var dqname, dqrl, err_1, client, params, cmd, data, dqrl;
60
+ return __generator(this, function (_a) {
61
+ switch (_a.label) {
62
+ case 0:
63
+ debug('getOrCreateDLQ(', queue, ')');
64
+ dqname = (0, qrlCache_js_1.normalizeDLQName)(queue, opt);
65
+ _a.label = 1;
66
+ case 1:
67
+ _a.trys.push([1, 3, , 5]);
68
+ return [4 /*yield*/, (0, qrlCache_js_1.qrlCacheGet)(dqname)];
69
+ case 2:
70
+ dqrl = _a.sent();
71
+ return [2 /*return*/, dqrl];
72
+ case 3:
73
+ err_1 = _a.sent();
74
+ // Anything other than queue doesn't exist gets re-thrown
75
+ if (!(err_1 instanceof client_sqs_1.QueueDoesNotExist))
76
+ throw err_1;
77
+ client = (0, sqs_js_1.getSQSClient)();
78
+ params = {
79
+ Attributes: { MessageRetentionPeriod: opt.messageRetentionPeriod + '' },
80
+ QueueName: dqname
81
+ };
82
+ if (opt.tags)
83
+ params.tags = opt.tags;
84
+ if (opt.fifo)
85
+ params.Attributes.FifoQueue = 'true';
86
+ cmd = new client_sqs_1.CreateQueueCommand(params);
87
+ if (opt.verbose)
88
+ console.error(chalk_1.default.blue('Creating dead letter queue ') + dqname);
89
+ return [4 /*yield*/, client.send(cmd)];
90
+ case 4:
91
+ data = _a.sent();
92
+ debug('createQueue returned', data);
93
+ dqrl = data.QueueUrl;
94
+ (0, qrlCache_js_1.qrlCacheSet)(dqname, dqrl);
95
+ return [2 /*return*/, dqrl];
96
+ case 5: return [2 /*return*/];
97
+ }
98
+ });
99
+ });
100
+ }
101
+ exports.getOrCreateDLQ = getOrCreateDLQ;
102
+ function getOrCreateFailQueue(queue, opt) {
103
+ return __awaiter(this, void 0, void 0, function () {
104
+ var fqname, fqrl, err_2, client, params, dqrl, dqa, cmd, data, fqrl;
105
+ return __generator(this, function (_a) {
106
+ switch (_a.label) {
107
+ case 0:
108
+ debug('getOrCreateFailQueue(', queue, ')');
109
+ fqname = (0, qrlCache_js_1.normalizeFailQueueName)(queue, opt);
110
+ _a.label = 1;
111
+ case 1:
112
+ _a.trys.push([1, 3, , 8]);
113
+ return [4 /*yield*/, (0, qrlCache_js_1.qrlCacheGet)(fqname)];
114
+ case 2:
115
+ fqrl = _a.sent();
116
+ return [2 /*return*/, fqrl];
117
+ case 3:
118
+ err_2 = _a.sent();
119
+ // Anything other than queue doesn't exist gets re-thrown
120
+ if (!(err_2 instanceof client_sqs_1.QueueDoesNotExist))
121
+ throw err_2;
122
+ client = (0, sqs_js_1.getSQSClient)();
123
+ params = {
124
+ Attributes: { MessageRetentionPeriod: opt.messageRetentionPeriod + '' },
125
+ QueueName: fqname
126
+ };
127
+ if (!opt.dlq) return [3 /*break*/, 6];
128
+ return [4 /*yield*/, getOrCreateDLQ(queue, opt)];
129
+ case 4:
130
+ dqrl = _a.sent();
131
+ return [4 /*yield*/, getQueueAttributes(dqrl)];
132
+ case 5:
133
+ dqa = _a.sent();
134
+ debug('dqa', dqa);
135
+ params.Attributes.RedrivePolicy = JSON.stringify({
136
+ deadLetterTargetArn: dqa.Attributes.QueueArn,
137
+ maxReceiveCount: opt.dlqAfter + ''
138
+ });
139
+ _a.label = 6;
140
+ case 6:
141
+ if (opt.tags)
142
+ params.tags = opt.tags;
143
+ if (opt.fifo)
144
+ params.Attributes.FifoQueue = 'true';
145
+ cmd = new client_sqs_1.CreateQueueCommand(params);
146
+ if (opt.verbose)
147
+ console.error(chalk_1.default.blue('Creating fail queue ') + fqname);
148
+ return [4 /*yield*/, client.send(cmd)];
149
+ case 7:
150
+ data = _a.sent();
151
+ debug('createQueue returned', data);
152
+ fqrl = data.QueueUrl;
153
+ (0, qrlCache_js_1.qrlCacheSet)(fqname, fqrl);
154
+ return [2 /*return*/, fqrl];
155
+ case 8: return [2 /*return*/];
156
+ }
157
+ });
158
+ });
159
+ }
160
+ exports.getOrCreateFailQueue = getOrCreateFailQueue;
161
+ /**
162
+ * Returns a qrl for a queue that either exists or does not
163
+ */
164
+ function getOrCreateQueue(queue, opt) {
165
+ return __awaiter(this, void 0, void 0, function () {
166
+ var qname, qrl, err_3, fqrl, fqa, client, params, cmd, data, qrl;
167
+ return __generator(this, function (_a) {
168
+ switch (_a.label) {
169
+ case 0:
170
+ debug('getOrCreateQueue(', queue, ')');
171
+ qname = (0, qrlCache_js_1.normalizeQueueName)(queue, opt);
172
+ _a.label = 1;
173
+ case 1:
174
+ _a.trys.push([1, 3, , 7]);
175
+ return [4 /*yield*/, (0, qrlCache_js_1.qrlCacheGet)(qname)];
176
+ case 2:
177
+ qrl = _a.sent();
178
+ return [2 /*return*/, qrl];
179
+ case 3:
180
+ err_3 = _a.sent();
181
+ // Anything other than queue doesn't exist gets re-thrown
182
+ if (!(err_3 instanceof client_sqs_1.QueueDoesNotExist))
183
+ throw err_3;
184
+ return [4 /*yield*/, getOrCreateFailQueue(qname, opt)];
185
+ case 4:
186
+ fqrl = _a.sent();
187
+ return [4 /*yield*/, getQueueAttributes(fqrl)
188
+ // Create our queue
189
+ ];
190
+ case 5:
191
+ fqa = _a.sent();
192
+ client = (0, sqs_js_1.getSQSClient)();
193
+ params = {
194
+ Attributes: {
195
+ MessageRetentionPeriod: opt.messageRetentionPeriod + '',
196
+ RedrivePolicy: JSON.stringify({
197
+ deadLetterTargetArn: fqa.Attributes.QueueArn,
198
+ maxReceiveCount: '1'
199
+ })
200
+ },
201
+ QueueName: qname
202
+ };
203
+ if (opt.tags)
204
+ params.tags = opt.tags;
205
+ if (opt.fifo)
206
+ params.Attributes.FifoQueue = 'true';
207
+ cmd = new client_sqs_1.CreateQueueCommand(params);
208
+ debug({ params: params });
209
+ if (opt.verbose)
210
+ console.error(chalk_1.default.blue('Creating queue ') + qname);
211
+ return [4 /*yield*/, client.send(cmd)];
212
+ case 6:
213
+ data = _a.sent();
214
+ debug('createQueue returned', data);
215
+ qrl = data.QueueUrl;
216
+ (0, qrlCache_js_1.qrlCacheSet)(qname, qrl);
217
+ return [2 /*return*/, qrl];
218
+ case 7: return [2 /*return*/];
219
+ }
220
+ });
221
+ });
222
+ }
223
+ exports.getOrCreateQueue = getOrCreateQueue;
224
+ function getQueueAttributes(qrl) {
225
+ return __awaiter(this, void 0, void 0, function () {
226
+ var client, params, cmd, data;
227
+ return __generator(this, function (_a) {
228
+ switch (_a.label) {
229
+ case 0:
230
+ debug('getQueueAttributes(', qrl, ')');
231
+ client = (0, sqs_js_1.getSQSClient)();
232
+ params = { AttributeNames: ['All'], QueueUrl: qrl };
233
+ cmd = new client_sqs_1.GetQueueAttributesCommand(params);
234
+ return [4 /*yield*/, client.send(cmd)];
235
+ case 1:
236
+ data = _a.sent();
237
+ debug('GetQueueAttributes returned', data);
238
+ return [2 /*return*/, data];
239
+ }
240
+ });
241
+ });
242
+ }
243
+ exports.getQueueAttributes = getQueueAttributes;
244
+ function formatMessage(command, id) {
245
+ var message = {
246
+ /*
247
+ MessageAttributes: {
248
+ City: { DataType: 'String', StringValue: 'Any City' },
249
+ Population: { DataType: 'Number', StringValue: '1250800' }
250
+ },
251
+ */
252
+ MessageBody: command
253
+ };
254
+ if (typeof id !== 'undefined')
255
+ message.Id = '' + id;
256
+ return message;
257
+ }
258
+ exports.formatMessage = formatMessage;
259
+ function sendMessage(qrl, command, opt) {
260
+ return __awaiter(this, void 0, void 0, function () {
261
+ var params, client, cmd, data;
262
+ return __generator(this, function (_a) {
263
+ switch (_a.label) {
264
+ case 0:
265
+ debug('sendMessage(', qrl, command, ')');
266
+ params = Object.assign({ QueueUrl: qrl }, formatMessage(command));
267
+ // Add in group id if we're using fifo
268
+ if (opt.fifo) {
269
+ params.MessageGroupId = opt.groupId;
270
+ params.MessageDeduplicationId = opt.deduplicationId;
271
+ }
272
+ if (opt.delay)
273
+ params.DelaySeconds = opt.delay;
274
+ client = (0, sqs_js_1.getSQSClient)();
275
+ cmd = new client_sqs_1.SendMessageCommand(params);
276
+ debug({ cmd: cmd });
277
+ return [4 /*yield*/, client.send(cmd)];
278
+ case 1:
279
+ data = _a.sent();
280
+ debug('sendMessage returned', data);
281
+ return [2 /*return*/, data];
282
+ }
283
+ });
284
+ });
285
+ }
286
+ exports.sendMessage = sendMessage;
287
+ function sendMessageBatch(qrl, messages, opt) {
288
+ return __awaiter(this, void 0, void 0, function () {
289
+ var params, uuidFunction, client, cmd, data;
290
+ return __generator(this, function (_a) {
291
+ switch (_a.label) {
292
+ case 0:
293
+ debug('sendMessageBatch(', qrl, messages.map(function (e) { return Object.assign(Object.assign({}, e), { MessageBody: e.MessageBody.slice(0, 10) + '...' }); }), ')');
294
+ params = { Entries: messages, QueueUrl: qrl };
295
+ uuidFunction = opt.uuidFunction || uuid_1.v1;
296
+ // Add in group id if we're using fifo
297
+ if (opt.fifo) {
298
+ params.Entries = params.Entries.map(function (message) { return Object.assign({
299
+ MessageGroupId: opt.groupIdPerMessage ? uuidFunction() : opt.groupId,
300
+ MessageDeduplicationId: uuidFunction()
301
+ }, message); });
302
+ }
303
+ if (opt.delay) {
304
+ params.Entries = params.Entries.map(function (message) {
305
+ return Object.assign({ DelaySeconds: opt.delay }, message);
306
+ });
307
+ }
308
+ client = (0, sqs_js_1.getSQSClient)();
309
+ cmd = new client_sqs_1.SendMessageBatchCommand(params);
310
+ debug({ cmd: cmd });
311
+ return [4 /*yield*/, client.send(cmd)];
312
+ case 1:
313
+ data = _a.sent();
314
+ debug('sendMessageBatch returned', data);
315
+ return [2 /*return*/, data];
316
+ }
317
+ });
318
+ });
319
+ }
320
+ exports.sendMessageBatch = sendMessageBatch;
321
+ var messages = {};
322
+ var requestCount = 0;
323
+ //
324
+ // Flushes the internal message buffer for qrl.
325
+ // If the message is too large, batch is retried with half the messages.
326
+ // Returns number of messages flushed.
327
+ //
328
+ function flushMessages(qrl, opt) {
329
+ return __awaiter(this, void 0, void 0, function () {
330
+ function whileNotEmpty() {
331
+ return __awaiter(this, void 0, void 0, function () {
332
+ var batch, nextSize, totalSize, data, err;
333
+ return __generator(this, function (_a) {
334
+ switch (_a.label) {
335
+ case 0:
336
+ if (!(messages[qrl] && messages[qrl].length))
337
+ return [2 /*return*/, numFlushed
338
+ // Construct batch until full
339
+ ];
340
+ batch = [];
341
+ nextSize = JSON.stringify(messages[qrl][0]).length;
342
+ totalSize = 0;
343
+ while ((totalSize + nextSize) < 262144 && messages[qrl].length && batch.length < 10) {
344
+ batch.push(messages[qrl].shift());
345
+ totalSize += nextSize;
346
+ if (messages[qrl].length)
347
+ nextSize = JSON.stringify(messages[qrl][0]).length;
348
+ else
349
+ nextSize = 0;
350
+ }
351
+ return [4 /*yield*/, sendMessageBatch(qrl, batch, opt)];
352
+ case 1:
353
+ data = _a.sent();
354
+ debug({ data: data });
355
+ // Fail if there are any individual message failures
356
+ if (data.Failed && data.Failed.length) {
357
+ err = new Error('One or more message failures: ' + JSON.stringify(data.Failed));
358
+ err.Failed = data.Failed;
359
+ throw err;
360
+ }
361
+ // If we actually managed to flush any of them
362
+ if (batch.length) {
363
+ requestCount += 1;
364
+ data.Successful.forEach(function (message) {
365
+ if (opt.verbose)
366
+ console.error(chalk_1.default.blue('Enqueued job ') + message.MessageId + chalk_1.default.blue(' request ' + requestCount));
367
+ });
368
+ numFlushed += batch.length;
369
+ }
370
+ return [2 /*return*/, whileNotEmpty()];
371
+ }
372
+ });
373
+ });
374
+ }
375
+ var numFlushed;
376
+ return __generator(this, function (_a) {
377
+ debug('flushMessages', qrl);
378
+ numFlushed = 0;
379
+ return [2 /*return*/, whileNotEmpty()];
380
+ });
381
+ });
382
+ }
383
+ exports.flushMessages = flushMessages;
384
+ //
385
+ // Adds a message to the inernal message buffer for the given qrl.
386
+ // Automaticaly flushes if queue has >= 10 messages.
387
+ // Returns number of messages flushed.
388
+ //
389
+ var messageIndex = 0;
390
+ function addMessage(qrl, command, opt) {
391
+ return __awaiter(this, void 0, void 0, function () {
392
+ var message;
393
+ return __generator(this, function (_a) {
394
+ message = formatMessage(command, messageIndex++);
395
+ messages[qrl] = messages[qrl] || [];
396
+ messages[qrl].push(message);
397
+ if (messages[qrl].length >= 10) {
398
+ return [2 /*return*/, flushMessages(qrl, opt)];
399
+ }
400
+ return [2 /*return*/, 0];
401
+ });
402
+ });
403
+ }
404
+ exports.addMessage = addMessage;
405
+ //
406
+ // Enqueue a single command
407
+ // Returns a promise for the SQS API response.
408
+ //
409
+ function enqueue(queue, command, options) {
410
+ return __awaiter(this, void 0, void 0, function () {
411
+ var opt, qrl;
412
+ return __generator(this, function (_a) {
413
+ switch (_a.label) {
414
+ case 0:
415
+ debug('enqueue(', { queue: queue, command: command }, ')');
416
+ opt = (0, defaults_js_1.getOptionsWithDefaults)(options);
417
+ return [4 /*yield*/, getOrCreateQueue(queue, opt)];
418
+ case 1:
419
+ qrl = _a.sent();
420
+ return [2 /*return*/, sendMessage(qrl, command, opt)];
421
+ }
422
+ });
423
+ });
424
+ }
425
+ exports.enqueue = enqueue;
426
+ //
427
+ // Enqueue many commands formatted as an array of {queue: ..., command: ...} pairs.
428
+ // Returns a promise for the total number of messages enqueued.
429
+ //
430
+ function enqueueBatch(pairs, options) {
431
+ return __awaiter(this, void 0, void 0, function () {
432
+ var opt, normalizedPairs, uniqueQnames, createPromises, _i, uniqueQnames_1, qname, addMessagePromises, _a, normalizedPairs_1, _b, qname, command, qrl, flushCounts, initialFlushTotal, extraFlushPromises, qrl, extraFlushCounts, extraFlushTotal, totalFlushed;
433
+ return __generator(this, function (_c) {
434
+ switch (_c.label) {
435
+ case 0:
436
+ debug('enqueueBatch(', pairs, ')');
437
+ opt = (0, defaults_js_1.getOptionsWithDefaults)(options);
438
+ normalizedPairs = pairs.map(function (_a) {
439
+ var queue = _a.queue, command = _a.command;
440
+ return ({
441
+ qname: (0, qrlCache_js_1.normalizeQueueName)(queue, opt),
442
+ command: command
443
+ });
444
+ });
445
+ uniqueQnames = new Set(normalizedPairs.map(function (p) { return p.qname; }));
446
+ createPromises = [];
447
+ for (_i = 0, uniqueQnames_1 = uniqueQnames; _i < uniqueQnames_1.length; _i++) {
448
+ qname = uniqueQnames_1[_i];
449
+ createPromises.push(getOrCreateQueue(qname, opt));
450
+ }
451
+ return [4 /*yield*/, Promise.all(createPromises)
452
+ // After we've prefetched, all qrls are in cache
453
+ // so go back through the list of pairs and fire off messages
454
+ ];
455
+ case 1:
456
+ _c.sent();
457
+ // After we've prefetched, all qrls are in cache
458
+ // so go back through the list of pairs and fire off messages
459
+ requestCount = 0;
460
+ addMessagePromises = [];
461
+ _a = 0, normalizedPairs_1 = normalizedPairs;
462
+ _c.label = 2;
463
+ case 2:
464
+ if (!(_a < normalizedPairs_1.length)) return [3 /*break*/, 5];
465
+ _b = normalizedPairs_1[_a], qname = _b.qname, command = _b.command;
466
+ return [4 /*yield*/, getOrCreateQueue(qname, opt)];
467
+ case 3:
468
+ qrl = _c.sent();
469
+ addMessagePromises.push(addMessage(qrl, command, opt));
470
+ _c.label = 4;
471
+ case 4:
472
+ _a++;
473
+ return [3 /*break*/, 2];
474
+ case 5: return [4 /*yield*/, Promise.all(addMessagePromises)
475
+ // Count up how many were flushed during add
476
+ ];
477
+ case 6:
478
+ flushCounts = _c.sent();
479
+ // Count up how many were flushed during add
480
+ debug('flushCounts', flushCounts);
481
+ initialFlushTotal = flushCounts.reduce(function (a, b) { return a + b; }, 0);
482
+ extraFlushPromises = [];
483
+ for (qrl in messages) {
484
+ extraFlushPromises.push(flushMessages(qrl, opt));
485
+ }
486
+ return [4 /*yield*/, Promise.all(extraFlushPromises)];
487
+ case 7:
488
+ extraFlushCounts = _c.sent();
489
+ extraFlushTotal = extraFlushCounts.reduce(function (a, b) { return a + b; }, 0);
490
+ totalFlushed = initialFlushTotal + extraFlushTotal;
491
+ debug({ initialFlushTotal: initialFlushTotal, extraFlushTotal: extraFlushTotal, totalFlushed: totalFlushed });
492
+ return [2 /*return*/, totalFlushed];
493
+ }
494
+ });
495
+ });
496
+ }
497
+ exports.enqueueBatch = enqueueBatch;
498
+ debug('loaded');