qdone 2.0.29-alpha → 2.0.30-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/commonjs/src/cache.js +22 -93
- package/commonjs/src/cloudWatch.js +65 -111
- package/commonjs/src/consumer.js +135 -237
- package/commonjs/src/defaults.js +11 -11
- package/commonjs/src/enqueue.js +311 -503
- package/commonjs/src/exponentialBackoff.js +39 -110
- package/commonjs/src/idleQueues.js +255 -396
- package/commonjs/src/monitor.js +42 -115
- package/commonjs/src/qrlCache.js +80 -162
- package/commonjs/src/scheduler/jobExecutor.js +305 -363
- package/commonjs/src/scheduler/queueManager.js +111 -198
- package/commonjs/src/scheduler/systemMonitor.js +24 -28
- package/commonjs/src/sqs.js +58 -141
- package/package.json +2 -2
- package/src/consumer.js +3 -5
- package/src/defaults.js +3 -3
- package/src/enqueue.js +1 -1
- package/src/scheduler/jobExecutor.js +77 -33
- package/src/scheduler/queueManager.js +1 -1
package/commonjs/src/enqueue.js
CHANGED
|
@@ -1,246 +1,153 @@
|
|
|
1
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
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
39
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
40
4
|
};
|
|
41
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
6
|
exports.enqueueBatch = exports.enqueue = exports.addMessage = exports.flushMessages = exports.sendMessageBatch = exports.sendMessage = exports.formatMessage = exports.getQueueAttributes = exports.getOrCreateQueue = exports.getOrCreateFailQueue = exports.getOrCreateDLQ = void 0;
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
function getOrCreateDLQ(queue, opt) {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
if (opt.verbose)
|
|
84
|
-
console.error(chalk_1.default.blue('Creating dead letter queue ') + dqname);
|
|
85
|
-
return [4 /*yield*/, client.send(cmd)];
|
|
86
|
-
case 4:
|
|
87
|
-
data = _a.sent();
|
|
88
|
-
debug('createQueue returned', data);
|
|
89
|
-
dqrl = data.QueueUrl;
|
|
90
|
-
(0, qrlCache_js_1.qrlCacheSet)(dqname, dqrl);
|
|
91
|
-
return [2 /*return*/, dqrl];
|
|
92
|
-
case 5: return [2 /*return*/];
|
|
93
|
-
}
|
|
94
|
-
});
|
|
95
|
-
});
|
|
7
|
+
const node_1 = require("@sentry/node");
|
|
8
|
+
const uuid_1 = require("uuid");
|
|
9
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
10
|
+
const debug_1 = __importDefault(require("debug"));
|
|
11
|
+
const client_sqs_1 = require("@aws-sdk/client-sqs");
|
|
12
|
+
const qrlCache_js_1 = require("./qrlCache.js");
|
|
13
|
+
const sqs_js_1 = require("./sqs.js");
|
|
14
|
+
const defaults_js_1 = require("./defaults.js");
|
|
15
|
+
const exponentialBackoff_js_1 = require("./exponentialBackoff.js");
|
|
16
|
+
const debug = (0, debug_1.default)('qdone:enqueue');
|
|
17
|
+
async function getOrCreateDLQ(queue, opt) {
|
|
18
|
+
debug('getOrCreateDLQ(', queue, ')');
|
|
19
|
+
const dqname = (0, qrlCache_js_1.normalizeDLQName)(queue, opt);
|
|
20
|
+
try {
|
|
21
|
+
const dqrl = await (0, qrlCache_js_1.qrlCacheGet)(dqname);
|
|
22
|
+
return dqrl;
|
|
23
|
+
}
|
|
24
|
+
catch (err) {
|
|
25
|
+
// Anything other than queue doesn't exist gets re-thrown
|
|
26
|
+
if (!(err instanceof client_sqs_1.QueueDoesNotExist))
|
|
27
|
+
throw err;
|
|
28
|
+
// Create our DLQ
|
|
29
|
+
const client = (0, sqs_js_1.getSQSClient)();
|
|
30
|
+
const params = {
|
|
31
|
+
Attributes: { MessageRetentionPeriod: opt.messageRetentionPeriod + '' },
|
|
32
|
+
QueueName: dqname
|
|
33
|
+
};
|
|
34
|
+
if (opt.tags)
|
|
35
|
+
params.tags = opt.tags;
|
|
36
|
+
if (opt.fifo)
|
|
37
|
+
params.Attributes.FifoQueue = 'true';
|
|
38
|
+
const cmd = new client_sqs_1.CreateQueueCommand(params);
|
|
39
|
+
if (opt.verbose)
|
|
40
|
+
console.error(chalk_1.default.blue('Creating dead letter queue ') + dqname);
|
|
41
|
+
const data = await client.send(cmd);
|
|
42
|
+
debug('createQueue returned', data);
|
|
43
|
+
const dqrl = data.QueueUrl;
|
|
44
|
+
(0, qrlCache_js_1.qrlCacheSet)(dqname, dqrl);
|
|
45
|
+
return dqrl;
|
|
46
|
+
}
|
|
96
47
|
}
|
|
97
48
|
exports.getOrCreateDLQ = getOrCreateDLQ;
|
|
98
|
-
function getOrCreateFailQueue(queue, opt) {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
params.tags = opt.tags;
|
|
141
|
-
if (opt.fifo)
|
|
142
|
-
params.Attributes.FifoQueue = 'true';
|
|
143
|
-
cmd = new client_sqs_1.CreateQueueCommand(params);
|
|
144
|
-
if (opt.verbose)
|
|
145
|
-
console.error(chalk_1.default.blue('Creating fail queue ') + fqname);
|
|
146
|
-
return [4 /*yield*/, client.send(cmd)];
|
|
147
|
-
case 7:
|
|
148
|
-
data = _a.sent();
|
|
149
|
-
debug('createQueue returned', data);
|
|
150
|
-
fqrl = data.QueueUrl;
|
|
151
|
-
(0, qrlCache_js_1.qrlCacheSet)(fqname, fqrl);
|
|
152
|
-
return [2 /*return*/, fqrl];
|
|
153
|
-
case 8: return [2 /*return*/];
|
|
154
|
-
}
|
|
155
|
-
});
|
|
156
|
-
});
|
|
49
|
+
async function getOrCreateFailQueue(queue, opt) {
|
|
50
|
+
debug('getOrCreateFailQueue(', queue, ')');
|
|
51
|
+
const fqname = (0, qrlCache_js_1.normalizeFailQueueName)(queue, opt);
|
|
52
|
+
try {
|
|
53
|
+
const fqrl = await (0, qrlCache_js_1.qrlCacheGet)(fqname);
|
|
54
|
+
return fqrl;
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
// Anything other than queue doesn't exist gets re-thrown
|
|
58
|
+
if (!(err instanceof client_sqs_1.QueueDoesNotExist))
|
|
59
|
+
throw err;
|
|
60
|
+
// Crate our fail queue
|
|
61
|
+
const client = (0, sqs_js_1.getSQSClient)();
|
|
62
|
+
const params = {
|
|
63
|
+
Attributes: { MessageRetentionPeriod: opt.messageRetentionPeriod + '' },
|
|
64
|
+
QueueName: fqname
|
|
65
|
+
};
|
|
66
|
+
// If we have a dlq, we grab it and set a redrive policy
|
|
67
|
+
if (opt.dlq) {
|
|
68
|
+
const dqrl = await getOrCreateDLQ(queue, opt);
|
|
69
|
+
const dqa = await getQueueAttributes(dqrl);
|
|
70
|
+
debug('dqa', dqa);
|
|
71
|
+
params.Attributes.RedrivePolicy = JSON.stringify({
|
|
72
|
+
deadLetterTargetArn: dqa.Attributes.QueueArn,
|
|
73
|
+
maxReceiveCount: opt.dlqAfter + ''
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
if (opt.failDelay)
|
|
77
|
+
params.Attributes.DelaySeconds = opt.failDelay + '';
|
|
78
|
+
if (opt.tags)
|
|
79
|
+
params.tags = opt.tags;
|
|
80
|
+
if (opt.fifo)
|
|
81
|
+
params.Attributes.FifoQueue = 'true';
|
|
82
|
+
const cmd = new client_sqs_1.CreateQueueCommand(params);
|
|
83
|
+
if (opt.verbose)
|
|
84
|
+
console.error(chalk_1.default.blue('Creating fail queue ') + fqname);
|
|
85
|
+
const data = await client.send(cmd);
|
|
86
|
+
debug('createQueue returned', data);
|
|
87
|
+
const fqrl = data.QueueUrl;
|
|
88
|
+
(0, qrlCache_js_1.qrlCacheSet)(fqname, fqrl);
|
|
89
|
+
return fqrl;
|
|
90
|
+
}
|
|
157
91
|
}
|
|
158
92
|
exports.getOrCreateFailQueue = getOrCreateFailQueue;
|
|
159
93
|
/**
|
|
160
94
|
* Returns a qrl for a queue that either exists or does not
|
|
161
95
|
*/
|
|
162
|
-
function getOrCreateQueue(queue, opt) {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
params.tags = opt.tags;
|
|
203
|
-
if (opt.fifo)
|
|
204
|
-
params.Attributes.FifoQueue = 'true';
|
|
205
|
-
cmd = new client_sqs_1.CreateQueueCommand(params);
|
|
206
|
-
debug({ params: params });
|
|
207
|
-
if (opt.verbose)
|
|
208
|
-
console.error(chalk_1.default.blue('Creating queue ') + qname);
|
|
209
|
-
return [4 /*yield*/, client.send(cmd)];
|
|
210
|
-
case 6:
|
|
211
|
-
data = _a.sent();
|
|
212
|
-
debug('createQueue returned', data);
|
|
213
|
-
qrl = data.QueueUrl;
|
|
214
|
-
(0, qrlCache_js_1.qrlCacheSet)(qname, qrl);
|
|
215
|
-
return [2 /*return*/, qrl];
|
|
216
|
-
case 7: return [2 /*return*/];
|
|
217
|
-
}
|
|
218
|
-
});
|
|
219
|
-
});
|
|
96
|
+
async function getOrCreateQueue(queue, opt) {
|
|
97
|
+
debug('getOrCreateQueue(', queue, ')');
|
|
98
|
+
const qname = (0, qrlCache_js_1.normalizeQueueName)(queue, opt);
|
|
99
|
+
try {
|
|
100
|
+
const qrl = await (0, qrlCache_js_1.qrlCacheGet)(qname);
|
|
101
|
+
return qrl;
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
// Anything other than queue doesn't exist gets re-thrown
|
|
105
|
+
if (!(err instanceof client_sqs_1.QueueDoesNotExist))
|
|
106
|
+
throw err;
|
|
107
|
+
// Get our fail queue so we can create our own
|
|
108
|
+
const fqrl = await getOrCreateFailQueue(qname, opt);
|
|
109
|
+
const fqa = await getQueueAttributes(fqrl);
|
|
110
|
+
// Create our queue
|
|
111
|
+
const client = (0, sqs_js_1.getSQSClient)();
|
|
112
|
+
const params = {
|
|
113
|
+
Attributes: {
|
|
114
|
+
MessageRetentionPeriod: opt.messageRetentionPeriod + '',
|
|
115
|
+
RedrivePolicy: JSON.stringify({
|
|
116
|
+
deadLetterTargetArn: fqa.Attributes.QueueArn,
|
|
117
|
+
maxReceiveCount: '1'
|
|
118
|
+
})
|
|
119
|
+
},
|
|
120
|
+
QueueName: qname
|
|
121
|
+
};
|
|
122
|
+
if (opt.tags)
|
|
123
|
+
params.tags = opt.tags;
|
|
124
|
+
if (opt.fifo)
|
|
125
|
+
params.Attributes.FifoQueue = 'true';
|
|
126
|
+
const cmd = new client_sqs_1.CreateQueueCommand(params);
|
|
127
|
+
debug({ params });
|
|
128
|
+
if (opt.verbose)
|
|
129
|
+
console.error(chalk_1.default.blue('Creating queue ') + qname);
|
|
130
|
+
const data = await client.send(cmd);
|
|
131
|
+
debug('createQueue returned', data);
|
|
132
|
+
const qrl = data.QueueUrl;
|
|
133
|
+
(0, qrlCache_js_1.qrlCacheSet)(qname, qrl);
|
|
134
|
+
return qrl;
|
|
135
|
+
}
|
|
220
136
|
}
|
|
221
137
|
exports.getOrCreateQueue = getOrCreateQueue;
|
|
222
|
-
function getQueueAttributes(qrl) {
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
cmd = new client_sqs_1.GetQueueAttributesCommand(params);
|
|
232
|
-
return [4 /*yield*/, client.send(cmd)];
|
|
233
|
-
case 1:
|
|
234
|
-
data = _a.sent();
|
|
235
|
-
debug('GetQueueAttributes returned', data);
|
|
236
|
-
return [2 /*return*/, data];
|
|
237
|
-
}
|
|
238
|
-
});
|
|
239
|
-
});
|
|
138
|
+
async function getQueueAttributes(qrl) {
|
|
139
|
+
debug('getQueueAttributes(', qrl, ')');
|
|
140
|
+
const client = (0, sqs_js_1.getSQSClient)();
|
|
141
|
+
const params = { AttributeNames: ['All'], QueueUrl: qrl };
|
|
142
|
+
const cmd = new client_sqs_1.GetQueueAttributesCommand(params);
|
|
143
|
+
// debug({ cmd })
|
|
144
|
+
const data = await client.send(cmd);
|
|
145
|
+
debug('GetQueueAttributes returned', data);
|
|
146
|
+
return data;
|
|
240
147
|
}
|
|
241
148
|
exports.getQueueAttributes = getQueueAttributes;
|
|
242
149
|
function formatMessage(command, id) {
|
|
243
|
-
|
|
150
|
+
const message = {
|
|
244
151
|
/*
|
|
245
152
|
MessageAttributes: {
|
|
246
153
|
City: { DataType: 'String', StringValue: 'Any City' },
|
|
@@ -255,211 +162,155 @@ function formatMessage(command, id) {
|
|
|
255
162
|
}
|
|
256
163
|
exports.formatMessage = formatMessage;
|
|
257
164
|
// Retry happens within the context of the send functions
|
|
258
|
-
|
|
165
|
+
const retryableExceptions = [
|
|
259
166
|
client_sqs_1.RequestThrottled,
|
|
260
167
|
client_sqs_1.KmsThrottled,
|
|
261
168
|
client_sqs_1.QueueDoesNotExist // Queue could temporarily not exist due to eventual consistency, let it retry
|
|
262
169
|
];
|
|
263
|
-
function sendMessage(qrl, command, opt) {
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
return [4 /*yield*/, client.send(cmd)];
|
|
289
|
-
case 1:
|
|
290
|
-
data = _a.sent();
|
|
291
|
-
debug('sendMessage returned', data);
|
|
292
|
-
return [2 /*return*/, data];
|
|
293
|
-
}
|
|
294
|
-
});
|
|
295
|
-
}); };
|
|
296
|
-
shouldRetry = function (result, error) { return __awaiter(_this, void 0, void 0, function () {
|
|
297
|
-
var _i, retryableExceptions_1, exceptionClass;
|
|
298
|
-
return __generator(this, function (_a) {
|
|
299
|
-
for (_i = 0, retryableExceptions_1 = retryableExceptions; _i < retryableExceptions_1.length; _i++) {
|
|
300
|
-
exceptionClass = retryableExceptions_1[_i];
|
|
301
|
-
if (error instanceof exceptionClass) {
|
|
302
|
-
debug({ sendMessageRetryingBecause: { error: error, result: result } });
|
|
303
|
-
return [2 /*return*/, true];
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
return [2 /*return*/, false];
|
|
307
|
-
});
|
|
308
|
-
}); };
|
|
309
|
-
return [4 /*yield*/, backoff.run(send, shouldRetry)];
|
|
310
|
-
case 1:
|
|
311
|
-
result = _a.sent();
|
|
312
|
-
debug({ sendMessageResult: result });
|
|
313
|
-
return [2 /*return*/, result];
|
|
170
|
+
async function sendMessage(qrl, command, opt) {
|
|
171
|
+
debug('sendMessage(', qrl, command, ')');
|
|
172
|
+
const params = Object.assign({ QueueUrl: qrl }, formatMessage(command));
|
|
173
|
+
if (opt.fifo) {
|
|
174
|
+
params.MessageGroupId = opt.groupId;
|
|
175
|
+
params.MessageDeduplicationId = opt.deduplicationId || (0, uuid_1.v1)();
|
|
176
|
+
}
|
|
177
|
+
if (opt.delay)
|
|
178
|
+
params.DelaySeconds = opt.delay;
|
|
179
|
+
// Send it
|
|
180
|
+
const client = (0, sqs_js_1.getSQSClient)();
|
|
181
|
+
const cmd = new client_sqs_1.SendMessageCommand(params);
|
|
182
|
+
debug({ cmd });
|
|
183
|
+
const backoff = new exponentialBackoff_js_1.ExponentialBackoff(opt.sendRetries);
|
|
184
|
+
const send = async (attemptNumber) => {
|
|
185
|
+
cmd.input.attemptNumber = attemptNumber;
|
|
186
|
+
const data = await client.send(cmd);
|
|
187
|
+
debug('sendMessage returned', data);
|
|
188
|
+
return data;
|
|
189
|
+
};
|
|
190
|
+
const shouldRetry = async (result, error) => {
|
|
191
|
+
for (const exceptionClass of retryableExceptions) {
|
|
192
|
+
if (error instanceof exceptionClass) {
|
|
193
|
+
debug({ sendMessageRetryingBecause: { error, result } });
|
|
194
|
+
return true;
|
|
314
195
|
}
|
|
315
|
-
}
|
|
316
|
-
|
|
196
|
+
}
|
|
197
|
+
return false;
|
|
198
|
+
};
|
|
199
|
+
const result = await backoff.run(send, shouldRetry);
|
|
200
|
+
debug({ sendMessageResult: result });
|
|
201
|
+
return result;
|
|
317
202
|
}
|
|
318
203
|
exports.sendMessage = sendMessage;
|
|
319
|
-
function sendMessageBatch(qrl, messages, opt) {
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
return [2 /*return*/, data];
|
|
357
|
-
}
|
|
358
|
-
});
|
|
359
|
-
}); };
|
|
360
|
-
shouldRetry = function (result, error) {
|
|
361
|
-
debug({ shouldRetry: { error: error, result: result } });
|
|
362
|
-
if (result) {
|
|
363
|
-
// Handle failed result of one or more messages in the batch
|
|
364
|
-
if (result.Failed && result.Failed.length) {
|
|
365
|
-
var _loop_1 = function (failed) {
|
|
366
|
-
// Find corresponding messages
|
|
367
|
-
var original = params.Entries.find(function (e) { return e.Id === failed.Id; });
|
|
368
|
-
var info = { failed: failed, original: original, opt: opt };
|
|
369
|
-
if (opt.sentryDsn) {
|
|
370
|
-
(0, node_1.addBreadcrumb)({ category: 'sendMessageBatch', message: 'Failed message: ' + JSON.stringify(info), level: 'error' });
|
|
371
|
-
}
|
|
372
|
-
else {
|
|
373
|
-
console.error(info);
|
|
374
|
-
}
|
|
375
|
-
};
|
|
376
|
-
for (var _i = 0, _a = result.Failed; _i < _a.length; _i++) {
|
|
377
|
-
var failed = _a[_i];
|
|
378
|
-
_loop_1(failed);
|
|
379
|
-
}
|
|
380
|
-
throw new Error('One or more message failures: ' + JSON.stringify(result.Failed));
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
if (error) {
|
|
384
|
-
// Handle a failed result from an overall error on request
|
|
204
|
+
async function sendMessageBatch(qrl, messages, opt) {
|
|
205
|
+
debug('sendMessageBatch(', qrl, messages.map(e => Object.assign(Object.assign({}, e), { MessageBody: e.MessageBody.slice(0, 10) + '...' })), ')');
|
|
206
|
+
const params = { Entries: messages, QueueUrl: qrl };
|
|
207
|
+
const uuidFunction = opt.uuidFunction || uuid_1.v1;
|
|
208
|
+
// Add in group id if we're using fifo
|
|
209
|
+
if (opt.fifo) {
|
|
210
|
+
params.Entries = params.Entries.map(message => Object.assign({
|
|
211
|
+
MessageGroupId: opt.groupIdPerMessage ? uuidFunction() : opt.groupId,
|
|
212
|
+
MessageDeduplicationId: opt.deduplicationId || uuidFunction()
|
|
213
|
+
}, message));
|
|
214
|
+
}
|
|
215
|
+
if (opt.delay) {
|
|
216
|
+
params.Entries = params.Entries.map(message => Object.assign({ DelaySeconds: opt.delay }, message));
|
|
217
|
+
}
|
|
218
|
+
if (opt.sentryDsn) {
|
|
219
|
+
(0, node_1.addBreadcrumb)({ category: 'sendMessageBatch', message: JSON.stringify({ params }), level: 'debug' });
|
|
220
|
+
}
|
|
221
|
+
debug({ params });
|
|
222
|
+
// Send them
|
|
223
|
+
const client = (0, sqs_js_1.getSQSClient)();
|
|
224
|
+
const cmd = new client_sqs_1.SendMessageBatchCommand(params);
|
|
225
|
+
debug({ cmd });
|
|
226
|
+
const backoff = new exponentialBackoff_js_1.ExponentialBackoff(opt.sendRetries);
|
|
227
|
+
const send = async (attemptNumber) => {
|
|
228
|
+
debug({ sendMessageBatchSend: { attemptNumber, params } });
|
|
229
|
+
const data = await client.send(cmd);
|
|
230
|
+
return data;
|
|
231
|
+
};
|
|
232
|
+
const shouldRetry = (result, error) => {
|
|
233
|
+
debug({ shouldRetry: { error, result } });
|
|
234
|
+
if (result) {
|
|
235
|
+
// Handle failed result of one or more messages in the batch
|
|
236
|
+
if (result.Failed && result.Failed.length) {
|
|
237
|
+
for (const failed of result.Failed) {
|
|
238
|
+
// Find corresponding messages
|
|
239
|
+
const original = params.Entries.find((e) => e.Id === failed.Id);
|
|
240
|
+
const info = { failed, original, opt };
|
|
385
241
|
if (opt.sentryDsn) {
|
|
386
|
-
(0, node_1.addBreadcrumb)({ category: 'sendMessageBatch', message: JSON.stringify(
|
|
242
|
+
(0, node_1.addBreadcrumb)({ category: 'sendMessageBatch', message: 'Failed message: ' + JSON.stringify(info), level: 'error' });
|
|
387
243
|
}
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
debug({ exceptionClass: exceptionClass, retryableExceptions: retryableExceptions });
|
|
391
|
-
if (error instanceof exceptionClass) {
|
|
392
|
-
debug({ sendMessageRetryingBecause: { error: error, result: result } });
|
|
393
|
-
return true;
|
|
394
|
-
}
|
|
244
|
+
else {
|
|
245
|
+
console.error(info);
|
|
395
246
|
}
|
|
396
247
|
}
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
}
|
|
400
|
-
|
|
248
|
+
throw new Error('One or more message failures: ' + JSON.stringify(result.Failed));
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
if (error) {
|
|
252
|
+
// Handle a failed result from an overall error on request
|
|
253
|
+
if (opt.sentryDsn) {
|
|
254
|
+
(0, node_1.addBreadcrumb)({ category: 'sendMessageBatch', message: JSON.stringify({ error }), level: 'error' });
|
|
255
|
+
}
|
|
256
|
+
for (const exceptionClass of retryableExceptions) {
|
|
257
|
+
debug({ exceptionClass, retryableExceptions });
|
|
258
|
+
if (error instanceof exceptionClass) {
|
|
259
|
+
debug({ sendMessageRetryingBecause: { error, result } });
|
|
260
|
+
return true;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
return backoff.run(send, shouldRetry);
|
|
401
266
|
}
|
|
402
267
|
exports.sendMessageBatch = sendMessageBatch;
|
|
403
|
-
|
|
268
|
+
let requestCount = 0;
|
|
404
269
|
//
|
|
405
270
|
// Flushes the internal message buffer for qrl.
|
|
406
271
|
// If the message is too large, batch is retried with half the messages.
|
|
407
272
|
// Returns number of messages flushed.
|
|
408
273
|
//
|
|
409
|
-
function flushMessages(qrl, opt, sendBuffer) {
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
if (batch.length) {
|
|
444
|
-
requestCount += 1;
|
|
445
|
-
data.Successful.forEach(function (message) {
|
|
446
|
-
if (opt.verbose)
|
|
447
|
-
console.error(chalk_1.default.blue('Enqueued job ') + message.MessageId + chalk_1.default.blue(' request ' + requestCount));
|
|
448
|
-
});
|
|
449
|
-
numFlushed += batch.length;
|
|
450
|
-
}
|
|
451
|
-
return [2 /*return*/, whileNotEmpty()];
|
|
452
|
-
}
|
|
453
|
-
});
|
|
274
|
+
async function flushMessages(qrl, opt, sendBuffer) {
|
|
275
|
+
debug('flushMessages', qrl);
|
|
276
|
+
// Flush until empty
|
|
277
|
+
let numFlushed = 0;
|
|
278
|
+
async function whileNotEmpty() {
|
|
279
|
+
if (!(sendBuffer[qrl] && sendBuffer[qrl].length))
|
|
280
|
+
return numFlushed;
|
|
281
|
+
// Construct batch until full
|
|
282
|
+
const batch = [];
|
|
283
|
+
let nextSize = JSON.stringify(sendBuffer[qrl][0]).length;
|
|
284
|
+
let totalSize = 0;
|
|
285
|
+
while ((totalSize + nextSize) < 262144 && sendBuffer[qrl].length && batch.length < 10) {
|
|
286
|
+
batch.push(sendBuffer[qrl].shift());
|
|
287
|
+
totalSize += nextSize;
|
|
288
|
+
if (sendBuffer[qrl].length)
|
|
289
|
+
nextSize = JSON.stringify(sendBuffer[qrl][0]).length;
|
|
290
|
+
else
|
|
291
|
+
nextSize = 0;
|
|
292
|
+
}
|
|
293
|
+
// Send batch
|
|
294
|
+
const data = await sendMessageBatch(qrl, batch, opt);
|
|
295
|
+
debug({ data });
|
|
296
|
+
// Fail if there are any individual message failures
|
|
297
|
+
if (data.Failed && data.Failed.length) {
|
|
298
|
+
const err = new Error('One or more message failures: ' + JSON.stringify(data.Failed));
|
|
299
|
+
err.Failed = data.Failed;
|
|
300
|
+
throw err;
|
|
301
|
+
}
|
|
302
|
+
// If we actually managed to flush any of them
|
|
303
|
+
if (batch.length) {
|
|
304
|
+
requestCount += 1;
|
|
305
|
+
data.Successful.forEach(message => {
|
|
306
|
+
if (opt.verbose)
|
|
307
|
+
console.error(chalk_1.default.blue('Enqueued job ') + message.MessageId + chalk_1.default.blue(' request ' + requestCount));
|
|
454
308
|
});
|
|
309
|
+
numFlushed += batch.length;
|
|
455
310
|
}
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
numFlushed = 0;
|
|
460
|
-
return [2 /*return*/, whileNotEmpty()];
|
|
461
|
-
});
|
|
462
|
-
});
|
|
311
|
+
return whileNotEmpty();
|
|
312
|
+
}
|
|
313
|
+
return whileNotEmpty();
|
|
463
314
|
}
|
|
464
315
|
exports.flushMessages = flushMessages;
|
|
465
316
|
//
|
|
@@ -467,111 +318,68 @@ exports.flushMessages = flushMessages;
|
|
|
467
318
|
// Automaticaly flushes if queue has >= 10 messages.
|
|
468
319
|
// Returns number of messages flushed.
|
|
469
320
|
//
|
|
470
|
-
function addMessage(qrl, command, messageIndex, opt, sendBuffer) {
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
return [2 /*return*/, flushMessages(qrl, opt, sendBuffer)];
|
|
480
|
-
}
|
|
481
|
-
return [2 /*return*/, 0];
|
|
482
|
-
});
|
|
483
|
-
});
|
|
321
|
+
async function addMessage(qrl, command, messageIndex, opt, sendBuffer) {
|
|
322
|
+
const message = formatMessage(command, messageIndex);
|
|
323
|
+
sendBuffer[qrl] = sendBuffer[qrl] || [];
|
|
324
|
+
sendBuffer[qrl].push(message);
|
|
325
|
+
debug({ location: 'addMessage', sendBuffer });
|
|
326
|
+
if (sendBuffer[qrl].length >= 10) {
|
|
327
|
+
return flushMessages(qrl, opt, sendBuffer);
|
|
328
|
+
}
|
|
329
|
+
return 0;
|
|
484
330
|
}
|
|
485
331
|
exports.addMessage = addMessage;
|
|
486
332
|
//
|
|
487
333
|
// Enqueue a single command
|
|
488
334
|
// Returns a promise for the SQS API response.
|
|
489
335
|
//
|
|
490
|
-
function enqueue(queue, command, options) {
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
case 0:
|
|
496
|
-
debug('enqueue(', { queue: queue, command: command }, ')');
|
|
497
|
-
opt = (0, defaults_js_1.getOptionsWithDefaults)(options);
|
|
498
|
-
return [4 /*yield*/, getOrCreateQueue(queue, opt)];
|
|
499
|
-
case 1:
|
|
500
|
-
qrl = _a.sent();
|
|
501
|
-
return [2 /*return*/, sendMessage(qrl, command, opt)];
|
|
502
|
-
}
|
|
503
|
-
});
|
|
504
|
-
});
|
|
336
|
+
async function enqueue(queue, command, options) {
|
|
337
|
+
debug('enqueue(', { queue, command }, ')');
|
|
338
|
+
const opt = (0, defaults_js_1.getOptionsWithDefaults)(options);
|
|
339
|
+
const qrl = await getOrCreateQueue(queue, opt);
|
|
340
|
+
return sendMessage(qrl, command, opt);
|
|
505
341
|
}
|
|
506
342
|
exports.enqueue = enqueue;
|
|
507
343
|
//
|
|
508
344
|
// Enqueue many commands formatted as an array of {queue: ..., command: ...} pairs.
|
|
509
345
|
// Returns a promise for the total number of messages enqueued.
|
|
510
346
|
//
|
|
511
|
-
function enqueueBatch(pairs, options) {
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
if (!(_a < normalizedPairs_1.length)) return [3 /*break*/, 6];
|
|
548
|
-
_b = normalizedPairs_1[_a], qname = _b.qname, command = _b.command;
|
|
549
|
-
return [4 /*yield*/, getOrCreateQueue(qname, opt)];
|
|
550
|
-
case 3:
|
|
551
|
-
qrl = _d.sent();
|
|
552
|
-
_c = initialFlushTotal;
|
|
553
|
-
return [4 /*yield*/, addMessage(qrl, command, messageIndex++, opt, sendBuffer)];
|
|
554
|
-
case 4:
|
|
555
|
-
initialFlushTotal = _c + _d.sent();
|
|
556
|
-
_d.label = 5;
|
|
557
|
-
case 5:
|
|
558
|
-
_a++;
|
|
559
|
-
return [3 /*break*/, 2];
|
|
560
|
-
case 6:
|
|
561
|
-
extraFlushPromises = [];
|
|
562
|
-
for (qrl in sendBuffer) {
|
|
563
|
-
extraFlushPromises.push(flushMessages(qrl, opt, sendBuffer));
|
|
564
|
-
}
|
|
565
|
-
return [4 /*yield*/, Promise.all(extraFlushPromises)];
|
|
566
|
-
case 7:
|
|
567
|
-
extraFlushCounts = _d.sent();
|
|
568
|
-
extraFlushTotal = extraFlushCounts.reduce(function (a, b) { return a + b; }, 0);
|
|
569
|
-
totalFlushed = initialFlushTotal + extraFlushTotal;
|
|
570
|
-
debug({ initialFlushTotal: initialFlushTotal, extraFlushTotal: extraFlushTotal, totalFlushed: totalFlushed });
|
|
571
|
-
return [2 /*return*/, totalFlushed];
|
|
572
|
-
}
|
|
573
|
-
});
|
|
574
|
-
});
|
|
347
|
+
async function enqueueBatch(pairs, options) {
|
|
348
|
+
debug('enqueueBatch(', pairs, ')');
|
|
349
|
+
const opt = (0, defaults_js_1.getOptionsWithDefaults)(options);
|
|
350
|
+
// Find unique queues so we can pre-fetch qrls. We do this so that all
|
|
351
|
+
// queues are created prior to going through our flush logic
|
|
352
|
+
const normalizedPairs = pairs.map(({ queue, command }) => ({
|
|
353
|
+
qname: (0, qrlCache_js_1.normalizeQueueName)(queue, opt),
|
|
354
|
+
command
|
|
355
|
+
}));
|
|
356
|
+
const uniqueQnames = new Set(normalizedPairs.map(p => p.qname));
|
|
357
|
+
// Prefetch qrls / create queues in parallel
|
|
358
|
+
const createPromises = [];
|
|
359
|
+
for (const qname of uniqueQnames) {
|
|
360
|
+
createPromises.push(getOrCreateQueue(qname, opt));
|
|
361
|
+
}
|
|
362
|
+
await Promise.all(createPromises);
|
|
363
|
+
// After we've prefetched, all qrls are in cache
|
|
364
|
+
// so go back through the list of pairs and fire off messages
|
|
365
|
+
requestCount = 0;
|
|
366
|
+
const sendBuffer = {};
|
|
367
|
+
let messageIndex = 0;
|
|
368
|
+
let initialFlushTotal = 0;
|
|
369
|
+
for (const { qname, command } of normalizedPairs) {
|
|
370
|
+
const qrl = await getOrCreateQueue(qname, opt);
|
|
371
|
+
initialFlushTotal += await addMessage(qrl, command, messageIndex++, opt, sendBuffer);
|
|
372
|
+
}
|
|
373
|
+
// And flush any remaining messages
|
|
374
|
+
const extraFlushPromises = [];
|
|
375
|
+
for (const qrl in sendBuffer) {
|
|
376
|
+
extraFlushPromises.push(flushMessages(qrl, opt, sendBuffer));
|
|
377
|
+
}
|
|
378
|
+
const extraFlushCounts = await Promise.all(extraFlushPromises);
|
|
379
|
+
const extraFlushTotal = extraFlushCounts.reduce((a, b) => a + b, 0);
|
|
380
|
+
const totalFlushed = initialFlushTotal + extraFlushTotal;
|
|
381
|
+
debug({ initialFlushTotal, extraFlushTotal, totalFlushed });
|
|
382
|
+
return totalFlushed;
|
|
575
383
|
}
|
|
576
384
|
exports.enqueueBatch = enqueueBatch;
|
|
577
385
|
debug('loaded');
|