qdone 2.0.9-alpha → 2.0.10-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/index.js +1 -2
- package/commonjs/src/consumer.js +73 -420
- package/commonjs/src/scheduler/jobExecutor.js +321 -0
- package/commonjs/src/scheduler/queueManager.js +145 -0
- package/commonjs/src/scheduler/systemMonitor.js +65 -0
- package/index.js +1 -1
- package/package.json +1 -1
- package/src/consumer.js +48 -317
- package/src/scheduler/jobExecutor.js +242 -0
- package/src/scheduler/queueManager.js +88 -0
- package/src/scheduler/systemMonitor.js +58 -0
package/commonjs/index.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.requestShutdown = exports.processMessages = exports.enqueueBatch = exports.enqueue = void 0;
|
|
4
4
|
var enqueue_js_1 = require("./src/enqueue.js");
|
|
5
5
|
Object.defineProperty(exports, "enqueue", { enumerable: true, get: function () { return enqueue_js_1.enqueue; } });
|
|
6
6
|
Object.defineProperty(exports, "enqueueBatch", { enumerable: true, get: function () { return enqueue_js_1.enqueueBatch; } });
|
|
7
7
|
var consumer_js_1 = require("./src/consumer.js");
|
|
8
8
|
Object.defineProperty(exports, "processMessages", { enumerable: true, get: function () { return consumer_js_1.processMessages; } });
|
|
9
9
|
Object.defineProperty(exports, "requestShutdown", { enumerable: true, get: function () { return consumer_js_1.requestShutdown; } });
|
|
10
|
-
Object.defineProperty(exports, "DoNotProcess", { enumerable: true, get: function () { return consumer_js_1.DoNotProcess; } });
|
package/commonjs/src/consumer.js
CHANGED
|
@@ -2,21 +2,6 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Consumer implementation.
|
|
4
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
5
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
21
6
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
22
7
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -57,32 +42,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
57
42
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
58
43
|
};
|
|
59
44
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
60
|
-
exports.processMessages = exports.
|
|
45
|
+
exports.processMessages = exports.getMessages = exports.requestShutdown = void 0;
|
|
61
46
|
var client_sqs_1 = require("@aws-sdk/client-sqs");
|
|
62
47
|
var chalk_1 = __importDefault(require("chalk"));
|
|
63
48
|
var debug_1 = __importDefault(require("debug"));
|
|
64
|
-
var
|
|
65
|
-
var
|
|
49
|
+
var systemMonitor_js_1 = require("./scheduler/systemMonitor.js");
|
|
50
|
+
var queueManager_js_1 = require("./scheduler/queueManager.js");
|
|
51
|
+
var jobExecutor_js_1 = require("./scheduler/jobExecutor.js");
|
|
66
52
|
var defaults_js_1 = require("./defaults.js");
|
|
67
53
|
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
54
|
var debug = (0, debug_1.default)('qdone:consumer');
|
|
87
55
|
// Global flag for shutdown request
|
|
88
56
|
var shutdownRequested = false;
|
|
@@ -99,421 +67,107 @@ function requestShutdown() {
|
|
|
99
67
|
debug('requestShutdown done');
|
|
100
68
|
}
|
|
101
69
|
exports.requestShutdown = requestShutdown;
|
|
102
|
-
function
|
|
103
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
104
|
-
function extendTimeout() {
|
|
105
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
106
|
-
var maxJobRun, jobRunTime, result, err_2;
|
|
107
|
-
return __generator(this, function (_a) {
|
|
108
|
-
switch (_a.label) {
|
|
109
|
-
case 0:
|
|
110
|
-
debug('extendTimeout');
|
|
111
|
-
maxJobRun = 12 * 60 * 60;
|
|
112
|
-
jobRunTime = ((new Date()) - jobStart) / 1000;
|
|
113
|
-
// Double every time, up to max
|
|
114
|
-
visibilityTimeout = Math.min(visibilityTimeout * 2, maxJobRun - jobRunTime, opt.killAfter - jobRunTime);
|
|
115
|
-
if (opt.verbose) {
|
|
116
|
-
console.error(chalk_1.default.blue(' Ran for ') + jobRunTime +
|
|
117
|
-
chalk_1.default.blue(' seconds, requesting another ') + visibilityTimeout +
|
|
118
|
-
chalk_1.default.blue(' seconds'));
|
|
119
|
-
}
|
|
120
|
-
_a.label = 1;
|
|
121
|
-
case 1:
|
|
122
|
-
_a.trys.push([1, 3, , 4]);
|
|
123
|
-
return [4 /*yield*/, (0, sqs_js_1.getSQSClient)().send(new client_sqs_1.ChangeMessageVisibilityCommand({
|
|
124
|
-
QueueUrl: qrl,
|
|
125
|
-
ReceiptHandle: message.ReceiptHandle,
|
|
126
|
-
VisibilityTimeout: visibilityTimeout
|
|
127
|
-
}))];
|
|
128
|
-
case 2:
|
|
129
|
-
result = _a.sent();
|
|
130
|
-
debug('ChangeMessageVisibility returned', result);
|
|
131
|
-
if (jobRunTime + visibilityTimeout >= maxJobRun ||
|
|
132
|
-
jobRunTime + visibilityTimeout >= opt.killAfter) {
|
|
133
|
-
if (opt.verbose)
|
|
134
|
-
console.error(chalk_1.default.yellow(' warning: this is our last time extension'));
|
|
135
|
-
}
|
|
136
|
-
else {
|
|
137
|
-
// Extend when we get 50% of the way to timeout
|
|
138
|
-
timeoutExtender = setTimeout(extendTimeout, visibilityTimeout * 1000 * 0.5);
|
|
139
|
-
}
|
|
140
|
-
return [3 /*break*/, 4];
|
|
141
|
-
case 3:
|
|
142
|
-
err_2 = _a.sent();
|
|
143
|
-
debug('ChangeMessageVisibility threw', err_2);
|
|
144
|
-
// Rejection means we're ouuta time, whatever, let the job die
|
|
145
|
-
if (opt.verbose) {
|
|
146
|
-
console.error(chalk_1.default.red(' failed to extend job: ') + err_2);
|
|
147
|
-
}
|
|
148
|
-
else if (!opt.disableLog) {
|
|
149
|
-
// Production error logging
|
|
150
|
-
console.log(JSON.stringify({
|
|
151
|
-
event: 'MESSAGE_PROCESSING_FAILED',
|
|
152
|
-
reason: 'ran longer than --kill-after',
|
|
153
|
-
timestamp: new Date(),
|
|
154
|
-
messageId: message.MessageId,
|
|
155
|
-
payload: payload,
|
|
156
|
-
errorMessage: err_2.toString().split('\n').slice(1).join('\n').trim() || undefined,
|
|
157
|
-
err: err_2
|
|
158
|
-
}));
|
|
159
|
-
}
|
|
160
|
-
return [3 /*break*/, 4];
|
|
161
|
-
case 4: return [2 /*return*/];
|
|
162
|
-
}
|
|
163
|
-
});
|
|
164
|
-
});
|
|
165
|
-
}
|
|
166
|
-
var payload, jobStart, visibilityTimeout, timeoutExtender, queue, result, err_1, result;
|
|
167
|
-
return __generator(this, function (_a) {
|
|
168
|
-
switch (_a.label) {
|
|
169
|
-
case 0:
|
|
170
|
-
debug('processMessage', message, qname, qrl);
|
|
171
|
-
payload = opt.json ? JSON.parse(message.Body) : message.Body;
|
|
172
|
-
if (opt.verbose) {
|
|
173
|
-
console.error(chalk_1.default.blue(' Processing payload:'), payload);
|
|
174
|
-
}
|
|
175
|
-
else if (!opt.disableLog) {
|
|
176
|
-
console.log(JSON.stringify({
|
|
177
|
-
event: 'MESSAGE_PROCESSING_START',
|
|
178
|
-
timestamp: new Date(),
|
|
179
|
-
messageId: message.MessageId,
|
|
180
|
-
payload: payload
|
|
181
|
-
}));
|
|
182
|
-
}
|
|
183
|
-
jobStart = new Date();
|
|
184
|
-
visibilityTimeout = 30 // this should be the queue timeout
|
|
185
|
-
;
|
|
186
|
-
// Extend when we get 50% of the way to timeout
|
|
187
|
-
timeoutExtender = setTimeout(extendTimeout, visibilityTimeout * 1000 * 0.5);
|
|
188
|
-
debug('timeout', visibilityTimeout * 1000 * 0.5);
|
|
189
|
-
_a.label = 1;
|
|
190
|
-
case 1:
|
|
191
|
-
_a.trys.push([1, 4, , 7]);
|
|
192
|
-
queue = qname.slice(opt.prefix.length);
|
|
193
|
-
return [4 /*yield*/, callback(queue, payload)];
|
|
194
|
-
case 2:
|
|
195
|
-
result = _a.sent();
|
|
196
|
-
debug('processMessage callback finished', { payload: payload, result: result });
|
|
197
|
-
clearTimeout(timeoutExtender);
|
|
198
|
-
if (opt.verbose) {
|
|
199
|
-
console.error(chalk_1.default.green(' SUCCESS'));
|
|
200
|
-
console.error(chalk_1.default.blue(' cleaning up (removing message) ...'));
|
|
201
|
-
}
|
|
202
|
-
return [4 /*yield*/, (0, sqs_js_1.getSQSClient)().send(new client_sqs_1.DeleteMessageCommand({
|
|
203
|
-
QueueUrl: qrl,
|
|
204
|
-
ReceiptHandle: message.ReceiptHandle
|
|
205
|
-
}))];
|
|
206
|
-
case 3:
|
|
207
|
-
_a.sent();
|
|
208
|
-
if (opt.verbose) {
|
|
209
|
-
console.error(chalk_1.default.blue(' done'));
|
|
210
|
-
console.error();
|
|
211
|
-
}
|
|
212
|
-
else if (!opt.disableLog) {
|
|
213
|
-
console.log(JSON.stringify({
|
|
214
|
-
event: 'MESSAGE_PROCESSING_COMPLETE',
|
|
215
|
-
timestamp: new Date(),
|
|
216
|
-
messageId: message.MessageId,
|
|
217
|
-
payload: payload
|
|
218
|
-
}));
|
|
219
|
-
}
|
|
220
|
-
return [2 /*return*/, { noJobs: 0, jobsSucceeded: 1, jobsFailed: 0 }];
|
|
221
|
-
case 4:
|
|
222
|
-
err_1 = _a.sent();
|
|
223
|
-
debug('exec.catch');
|
|
224
|
-
clearTimeout(timeoutExtender);
|
|
225
|
-
if (!(err_1 instanceof DoNotProcess)) return [3 /*break*/, 6];
|
|
226
|
-
if (opt.verbose) {
|
|
227
|
-
console.error(chalk_1.default.blue(' callback ') + chalk_1.default.yellow('REFUSED'));
|
|
228
|
-
console.error(chalk_1.default.blue(' cleaning up (removing message) ...'));
|
|
229
|
-
}
|
|
230
|
-
return [4 /*yield*/, (0, sqs_js_1.getSQSClient)().send(new client_sqs_1.ChangeMessageVisibilityCommand({
|
|
231
|
-
QueueUrl: qrl,
|
|
232
|
-
ReceiptHandle: message.ReceiptHandle,
|
|
233
|
-
VisibilityTimeout: 0
|
|
234
|
-
}))];
|
|
235
|
-
case 5:
|
|
236
|
-
result = _a.sent();
|
|
237
|
-
debug('ChangeMessageVisibility returned', result);
|
|
238
|
-
return [2 /*return*/, { noJobs: 1, jobsSucceeded: 0, jobsFailed: 0 }];
|
|
239
|
-
case 6:
|
|
240
|
-
// Fail path for job execution
|
|
241
|
-
if (opt.verbose) {
|
|
242
|
-
console.error(chalk_1.default.red(' FAILED'));
|
|
243
|
-
console.error(chalk_1.default.blue(' error : ') + err_1);
|
|
244
|
-
}
|
|
245
|
-
else if (!opt.disableLog) {
|
|
246
|
-
// Production error logging
|
|
247
|
-
console.log(JSON.stringify({
|
|
248
|
-
event: 'MESSAGE_PROCESSING_FAILED',
|
|
249
|
-
reason: 'exception thrown',
|
|
250
|
-
timestamp: new Date(),
|
|
251
|
-
messageId: message.MessageId,
|
|
252
|
-
payload: payload,
|
|
253
|
-
errorMessage: err_1.toString().split('\n').slice(1).join('\n').trim() || undefined,
|
|
254
|
-
err: err_1
|
|
255
|
-
}));
|
|
256
|
-
}
|
|
257
|
-
return [2 /*return*/, { noJobs: 0, jobsSucceeded: 0, jobsFailed: 1 }];
|
|
258
|
-
case 7: return [2 /*return*/];
|
|
259
|
-
}
|
|
260
|
-
});
|
|
261
|
-
});
|
|
262
|
-
}
|
|
263
|
-
exports.processMessage = processMessage;
|
|
264
|
-
//
|
|
265
|
-
// Pull work off of a single queue
|
|
266
|
-
//
|
|
267
|
-
function pollSingleQueue(qname, qrl, callback, opt) {
|
|
70
|
+
function getMessages(qrl, opt, maxMessages) {
|
|
268
71
|
return __awaiter(this, void 0, void 0, function () {
|
|
269
|
-
var params, response
|
|
72
|
+
var params, response;
|
|
270
73
|
return __generator(this, function (_a) {
|
|
271
74
|
switch (_a.label) {
|
|
272
75
|
case 0:
|
|
273
|
-
debug('pollSingleQueue', { qname: qname, qrl: qrl, callback: callback, opt: opt });
|
|
274
76
|
params = {
|
|
275
77
|
AttributeNames: ['All'],
|
|
276
|
-
MaxNumberOfMessages:
|
|
78
|
+
MaxNumberOfMessages: maxMessages,
|
|
277
79
|
MessageAttributeNames: ['All'],
|
|
278
80
|
QueueUrl: qrl,
|
|
279
81
|
VisibilityTimeout: 30,
|
|
280
82
|
WaitTimeSeconds: opt.waitTime
|
|
281
83
|
};
|
|
282
|
-
return [4 /*yield*/, (0, sqs_js_1.getSQSClient)().send(new client_sqs_1.ReceiveMessageCommand(params))
|
|
283
|
-
|
|
284
|
-
response = _a.sent();
|
|
285
|
-
debug('ReceiveMessage response', response);
|
|
286
|
-
if (shutdownRequested)
|
|
287
|
-
return [2 /*return*/, { noJobs: 0, jobsSucceeded: 0, jobsFailed: 0 }];
|
|
288
|
-
if (response.Messages) {
|
|
289
|
-
message = response.Messages[0];
|
|
290
|
-
if (opt.verbose)
|
|
291
|
-
console.error(chalk_1.default.blue(' Found message ' + message.MessageId));
|
|
292
|
-
return [2 /*return*/, processMessage(message, callback, qname, qrl, opt)];
|
|
293
|
-
}
|
|
294
|
-
else {
|
|
295
|
-
return [2 /*return*/, { noJobs: 1, jobsSucceeded: 0, jobsFailed: 0 }];
|
|
296
|
-
}
|
|
297
|
-
return [2 /*return*/];
|
|
298
|
-
}
|
|
299
|
-
});
|
|
300
|
-
});
|
|
301
|
-
}
|
|
302
|
-
exports.pollSingleQueue = pollSingleQueue;
|
|
303
|
-
//
|
|
304
|
-
// Resolve a set of queues
|
|
305
|
-
//
|
|
306
|
-
function resolveQueues(queues, opt) {
|
|
307
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
308
|
-
var qnames, pairs, activePairs, selectedPairs;
|
|
309
|
-
var _this = this;
|
|
310
|
-
return __generator(this, function (_a) {
|
|
311
|
-
switch (_a.label) {
|
|
312
|
-
case 0:
|
|
313
|
-
// Start processing
|
|
314
|
-
if (opt.verbose)
|
|
315
|
-
console.error(chalk_1.default.blue('Resolving queues: ') + queues.join(' '));
|
|
316
|
-
qnames = queues.map(function (queue) { return (0, qrlCache_js_1.normalizeQueueName)(queue, opt); });
|
|
317
|
-
return [4 /*yield*/, (0, qrlCache_js_1.getQnameUrlPairs)(qnames, opt)
|
|
318
|
-
// Figure out which pairs are active
|
|
84
|
+
return [4 /*yield*/, (0, sqs_js_1.getSQSClient)().send(new client_sqs_1.ReceiveMessageCommand(params))
|
|
85
|
+
// debug('ReceiveMessage response', response)
|
|
319
86
|
];
|
|
320
87
|
case 1:
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
debug({ pairsBeforeCheck: pairs });
|
|
325
|
-
return [4 /*yield*/, Promise.all(pairs.map(function (pair) { return __awaiter(_this, void 0, void 0, function () {
|
|
326
|
-
var idle;
|
|
327
|
-
return __generator(this, function (_a) {
|
|
328
|
-
switch (_a.label) {
|
|
329
|
-
case 0: return [4 /*yield*/, (0, idleQueues_js_1.cheapIdleCheck)(pair.qname, pair.qrl, opt)];
|
|
330
|
-
case 1:
|
|
331
|
-
idle = (_a.sent()).idle;
|
|
332
|
-
if (!idle)
|
|
333
|
-
activePairs.push(pair);
|
|
334
|
-
return [2 /*return*/];
|
|
335
|
-
}
|
|
336
|
-
});
|
|
337
|
-
}); }))];
|
|
338
|
-
case 2:
|
|
339
|
-
_a.sent();
|
|
340
|
-
_a.label = 3;
|
|
341
|
-
case 3:
|
|
342
|
-
// Finished resolving
|
|
343
|
-
debug('getQnameUrlPairs.then');
|
|
344
|
-
if (opt.verbose) {
|
|
345
|
-
console.error(chalk_1.default.blue(' done'));
|
|
346
|
-
console.error();
|
|
347
|
-
}
|
|
348
|
-
selectedPairs = (opt.activeOnly ? activePairs : pairs)
|
|
349
|
-
.filter(function (_a) {
|
|
350
|
-
var qname = _a.qname;
|
|
351
|
-
var suf = opt.failSuffix + (opt.fifo ? '.fifo' : '');
|
|
352
|
-
var isFailQueue = qname.slice(-suf.length) === suf;
|
|
353
|
-
var shouldInclude = opt.includeFailed ? true : !isFailQueue;
|
|
354
|
-
return shouldInclude;
|
|
355
|
-
});
|
|
356
|
-
return [2 /*return*/, selectedPairs];
|
|
88
|
+
response = _a.sent();
|
|
89
|
+
// debug('ReceiveMessage response', response)
|
|
90
|
+
return [2 /*return*/, response.Messages || []];
|
|
357
91
|
}
|
|
358
92
|
});
|
|
359
93
|
});
|
|
360
94
|
}
|
|
361
|
-
exports.
|
|
95
|
+
exports.getMessages = getMessages;
|
|
362
96
|
//
|
|
363
97
|
// Consumer
|
|
364
98
|
//
|
|
365
99
|
function processMessages(queues, callback, options) {
|
|
366
100
|
return __awaiter(this, void 0, void 0, function () {
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
if (activeLoops.length) {
|
|
372
|
-
console.error(chalk_1.default.blue('Waiting for work to finish on the following queues: '));
|
|
373
|
-
for (var _i = 0, activeLoops_2 = activeLoops; _i < activeLoops_2.length; _i++) {
|
|
374
|
-
var _a = activeLoops_2[_i], id = _a[0], _b = _a[1], qname = _b.qname, qrl = _b.qrl, promise = _b.promise;
|
|
375
|
-
console.error(' ' + qname + "job ".concat(id));
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
// clearTimeout(delayTimeout)
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
// Listen to a queue until it is out of messages
|
|
382
|
-
function listenLoop(qname, qrl, loopId) {
|
|
383
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
384
|
-
var _a, noJobs, jobsSucceeded, jobsFailed, err_3;
|
|
385
|
-
return __generator(this, function (_b) {
|
|
386
|
-
switch (_b.label) {
|
|
387
|
-
case 0:
|
|
388
|
-
_b.trys.push([0, 2, 3, 4]);
|
|
389
|
-
if (shutdownRequested)
|
|
390
|
-
return [2 /*return*/];
|
|
391
|
-
if (opt.verbose) {
|
|
392
|
-
console.error(chalk_1.default.blue('Looking for work on ') +
|
|
393
|
-
qname.slice(opt.prefix.length) +
|
|
394
|
-
chalk_1.default.blue(' (' + qrl + ')'));
|
|
395
|
-
}
|
|
396
|
-
return [4 /*yield*/, pollSingleQueue(qname, qrl, callback, opt)];
|
|
397
|
-
case 1:
|
|
398
|
-
_a = _b.sent(), noJobs = _a.noJobs, jobsSucceeded = _a.jobsSucceeded, jobsFailed = _a.jobsFailed;
|
|
399
|
-
debug('pollSingleQueue return');
|
|
400
|
-
stats.noJobs += noJobs;
|
|
401
|
-
stats.jobsFailed += jobsFailed;
|
|
402
|
-
stats.jobsSucceeded += jobsSucceeded;
|
|
403
|
-
debug({ stats: stats, noJobs: noJobs });
|
|
404
|
-
// No work? Shutdown requested? Return to outer loop
|
|
405
|
-
debug({ noJobs: noJobs, shutdownRequested: shutdownRequested });
|
|
406
|
-
if (noJobs || shutdownRequested)
|
|
407
|
-
return [2 /*return*/];
|
|
408
|
-
// Otherwise keep going
|
|
409
|
-
return [2 /*return*/, listenLoop(qname, qrl)];
|
|
410
|
-
case 2:
|
|
411
|
-
err_3 = _b.sent();
|
|
412
|
-
// TODO: Sentry
|
|
413
|
-
console.error(chalk_1.default.red(' ERROR in listenLoop'));
|
|
414
|
-
console.error(chalk_1.default.blue(' error : ') + err_3);
|
|
415
|
-
return [3 /*break*/, 4];
|
|
416
|
-
case 3:
|
|
417
|
-
completedLoops.set(loopId, activeLoops.get(loopId));
|
|
418
|
-
return [7 /*endfinally*/];
|
|
419
|
-
case 4: return [2 /*return*/];
|
|
420
|
-
}
|
|
421
|
-
});
|
|
422
|
-
});
|
|
423
|
-
}
|
|
424
|
-
var opt, loopCounter, stats, maxActiveLoops, activeLoops, completedLoops, delayTimeout, delay, start, selectedPairs, _i, selectedPairs_1, _a, qname, qrl, loopId, msSoFar, msUntilNextResolve, _b, completedLoops_1, _c, id, _d, qname, qrl, promise, _e, activeLoops_1, _f, id, _g, qname, qrl, promise;
|
|
425
|
-
return __generator(this, function (_h) {
|
|
426
|
-
switch (_h.label) {
|
|
101
|
+
var opt, systemMonitor, jobExecutor, queueManager, maxActiveJobs, delayTimeout, delay, activeQrls, maxReturnCount, listen, allowedJobs, maxLatency, latency, latencyFactor, targetJobs, jobsLeft, _i, _a, _b, qname, qrl, maxMessages;
|
|
102
|
+
var _this = this;
|
|
103
|
+
return __generator(this, function (_c) {
|
|
104
|
+
switch (_c.label) {
|
|
427
105
|
case 0:
|
|
428
106
|
opt = (0, defaults_js_1.getOptionsWithDefaults)(options);
|
|
429
107
|
debug('processMessages', { queues: queues, callback: callback, options: options, opt: opt });
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
108
|
+
systemMonitor = new systemMonitor_js_1.SystemMonitor(opt);
|
|
109
|
+
jobExecutor = new jobExecutor_js_1.JobExecutor(opt);
|
|
110
|
+
queueManager = new queueManager_js_1.QueueManager(opt, queues);
|
|
111
|
+
maxActiveJobs = 100;
|
|
112
|
+
debug({ systemMonitor: systemMonitor, jobExecutor: jobExecutor, queueManager: queueManager });
|
|
113
|
+
shutdownCallbacks.push(function () {
|
|
114
|
+
systemMonitor.shutdown();
|
|
115
|
+
queueManager.shutdown();
|
|
116
|
+
jobExecutor.shutdown();
|
|
117
|
+
});
|
|
435
118
|
delay = function (ms) { return new Promise(function (resolve) {
|
|
436
119
|
delayTimeout = setTimeout(resolve, ms);
|
|
437
120
|
}); };
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
return ' ' + qname.slice(opt.prefix.length) + chalk_1.default.blue(' - ' + qrl);
|
|
458
|
-
}).join('\n'));
|
|
459
|
-
console.error();
|
|
460
|
-
}
|
|
461
|
-
// Launch listen loop for each queue
|
|
462
|
-
for (_i = 0, selectedPairs_1 = selectedPairs; _i < selectedPairs_1.length; _i++) {
|
|
463
|
-
_a = selectedPairs_1[_i], qname = _a.qname, qrl = _a.qrl;
|
|
464
|
-
// Bail if we already have too many
|
|
465
|
-
if (activeLoops.size >= maxActiveLoops) {
|
|
466
|
-
if (opt.verbose)
|
|
467
|
-
console.error(chalk_1.default.yellow('Hit active worker limit of ') + maxActiveLoops);
|
|
468
|
-
break;
|
|
121
|
+
activeQrls = new Set();
|
|
122
|
+
maxReturnCount = 0;
|
|
123
|
+
listen = function (qname, qrl, maxMessages) { return __awaiter(_this, void 0, void 0, function () {
|
|
124
|
+
var messages, _i, messages_1, message;
|
|
125
|
+
return __generator(this, function (_a) {
|
|
126
|
+
switch (_a.label) {
|
|
127
|
+
case 0:
|
|
128
|
+
activeQrls.add(qrl);
|
|
129
|
+
maxReturnCount += maxMessages;
|
|
130
|
+
return [4 /*yield*/, getMessages(qrl, opt, maxMessages)];
|
|
131
|
+
case 1:
|
|
132
|
+
messages = _a.sent();
|
|
133
|
+
for (_i = 0, messages_1 = messages; _i < messages_1.length; _i++) {
|
|
134
|
+
message = messages_1[_i];
|
|
135
|
+
jobExecutor.executeJob(message, callback, qname, qrl);
|
|
136
|
+
}
|
|
137
|
+
maxReturnCount -= maxMessages;
|
|
138
|
+
activeQrls.delete(qrl);
|
|
139
|
+
return [2 /*return*/];
|
|
469
140
|
}
|
|
470
|
-
|
|
471
|
-
|
|
141
|
+
});
|
|
142
|
+
}); };
|
|
143
|
+
_c.label = 1;
|
|
144
|
+
case 1:
|
|
145
|
+
if (!!shutdownRequested) return [3 /*break*/, 3];
|
|
146
|
+
allowedJobs = maxActiveJobs - jobExecutor.activeJobCount() - maxReturnCount;
|
|
147
|
+
maxLatency = 100;
|
|
148
|
+
latency = systemMonitor.getLatency().setTimeout;
|
|
149
|
+
latencyFactor = 1 - Math.abs(Math.min(latency / maxLatency, 1)) // 0 if latency is at max, 1 if latency 0
|
|
150
|
+
;
|
|
151
|
+
targetJobs = Math.round(allowedJobs * latencyFactor);
|
|
152
|
+
debug({ allowedJobs: allowedJobs, maxLatency: maxLatency, latency: latency, latencyFactor: latencyFactor, targetJobs: targetJobs, activeQrls: activeQrls });
|
|
153
|
+
jobsLeft = targetJobs;
|
|
154
|
+
for (_i = 0, _a = queueManager.getPairs(); _i < _a.length; _i++) {
|
|
155
|
+
_b = _a[_i], qname = _b.qname, qrl = _b.qrl;
|
|
156
|
+
if (jobsLeft <= 0 || activeQrls.has(qrl))
|
|
157
|
+
continue;
|
|
158
|
+
maxMessages = Math.min(10, jobsLeft);
|
|
159
|
+
listen(qname, qrl, maxMessages);
|
|
160
|
+
jobsLeft -= maxMessages;
|
|
161
|
+
if (this.opt.verbose) {
|
|
162
|
+
console.error(chalk_1.default.blue('Listening on: '), qname);
|
|
472
163
|
}
|
|
164
|
+
debug({ listenedTo: { qname: qname, maxMessages: maxMessages, jobsLeft: jobsLeft } });
|
|
473
165
|
}
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
if (!msUntilNextResolve) return [3 /*break*/, 4];
|
|
479
|
-
if (opt.verbose)
|
|
480
|
-
console.error(chalk_1.default.blue('Will resolve queues again in ' + Math.round(msUntilNextResolve / 1000) + ' seconds'));
|
|
481
|
-
return [4 /*yield*/, delay(msUntilNextResolve)];
|
|
166
|
+
return [4 /*yield*/, delay(1000)];
|
|
167
|
+
case 2:
|
|
168
|
+
_c.sent();
|
|
169
|
+
return [3 /*break*/, 1];
|
|
482
170
|
case 3:
|
|
483
|
-
_h.sent();
|
|
484
|
-
_h.label = 4;
|
|
485
|
-
case 4:
|
|
486
|
-
_b = 0, completedLoops_1 = completedLoops;
|
|
487
|
-
_h.label = 5;
|
|
488
|
-
case 5:
|
|
489
|
-
if (!(_b < completedLoops_1.length)) return [3 /*break*/, 8];
|
|
490
|
-
_c = completedLoops_1[_b], id = _c[0], _d = _c[1], qname = _d.qname, qrl = _d.qrl, promise = _d.promise;
|
|
491
|
-
return [4 /*yield*/, promise]; // make sure the promise resolves
|
|
492
|
-
case 6:
|
|
493
|
-
_h.sent(); // make sure the promise resolves
|
|
494
|
-
debug('Cleaning up', { id: id, qname: qname, qrl: qrl, promise: promise });
|
|
495
|
-
activeLoops.delete(id);
|
|
496
|
-
_h.label = 7;
|
|
497
|
-
case 7:
|
|
498
|
-
_b++;
|
|
499
|
-
return [3 /*break*/, 5];
|
|
500
|
-
case 8: return [3 /*break*/, 1];
|
|
501
|
-
case 9:
|
|
502
|
-
debug('out here', { activeLoops: activeLoops });
|
|
503
|
-
_e = 0, activeLoops_1 = activeLoops;
|
|
504
|
-
_h.label = 10;
|
|
505
|
-
case 10:
|
|
506
|
-
if (!(_e < activeLoops_1.length)) return [3 /*break*/, 13];
|
|
507
|
-
_f = activeLoops_1[_e], id = _f[0], _g = _f[1], qname = _g.qname, qrl = _g.qrl, promise = _g.promise;
|
|
508
|
-
debug('Waiting on active loop', id);
|
|
509
|
-
return [4 /*yield*/, promise]; // make sure the promise resolves
|
|
510
|
-
case 11:
|
|
511
|
-
_h.sent(); // make sure the promise resolves
|
|
512
|
-
_h.label = 12;
|
|
513
|
-
case 12:
|
|
514
|
-
_e++;
|
|
515
|
-
return [3 /*break*/, 10];
|
|
516
|
-
case 13:
|
|
517
171
|
debug('after all');
|
|
518
172
|
return [2 /*return*/];
|
|
519
173
|
}
|
|
@@ -521,4 +175,3 @@ function processMessages(queues, callback, options) {
|
|
|
521
175
|
});
|
|
522
176
|
}
|
|
523
177
|
exports.processMessages = processMessages;
|
|
524
|
-
debug('loaded');
|