qdone 2.0.13-alpha → 2.0.15-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/consumer.js +94 -29
- package/commonjs/src/defaults.js +18 -1
- package/commonjs/src/idleQueues.js +2 -3
- package/commonjs/src/scheduler/jobExecutor.js +109 -60
- package/commonjs/src/scheduler/queueManager.js +122 -36
- package/commonjs/src/scheduler/systemMonitor.js +21 -37
- package/package.json +1 -1
- package/src/consumer.js +52 -23
- package/src/defaults.js +20 -1
- package/src/idleQueues.js +1 -1
- package/src/scheduler/jobExecutor.js +75 -30
- package/src/scheduler/queueManager.js +88 -24
- package/src/scheduler/systemMonitor.js +18 -32
|
@@ -47,7 +47,6 @@ var chalk_1 = __importDefault(require("chalk"));
|
|
|
47
47
|
var debug_1 = __importDefault(require("debug"));
|
|
48
48
|
var qrlCache_js_1 = require("../qrlCache.js");
|
|
49
49
|
var idleQueues_js_1 = require("../idleQueues.js");
|
|
50
|
-
var sqs_js_1 = require("../sqs.js");
|
|
51
50
|
var debug = (0, debug_1.default)('qdone:queueManager');
|
|
52
51
|
var QueueManager = /** @class */ (function () {
|
|
53
52
|
function QueueManager(opt, queues, resolveSeconds) {
|
|
@@ -56,72 +55,143 @@ var QueueManager = /** @class */ (function () {
|
|
|
56
55
|
this.queues = queues;
|
|
57
56
|
this.resolveSeconds = resolveSeconds;
|
|
58
57
|
this.selectedPairs = [];
|
|
58
|
+
this.icehouse = {};
|
|
59
59
|
this.resolveTimeout = undefined;
|
|
60
60
|
this.shutdownRequested = false;
|
|
61
|
-
this.resolveQueues();
|
|
61
|
+
this.resolvePromise = this.resolveQueues();
|
|
62
62
|
}
|
|
63
|
+
// Sends a queue to the icehouse, where it waits for a while before being
|
|
64
|
+
// checked again
|
|
65
|
+
QueueManager.prototype.updateIcehouse = function (qrl, emptyReceive) {
|
|
66
|
+
var foundEntry = !!this.icehouse[qrl];
|
|
67
|
+
var _a = this.icehouse[qrl] || {
|
|
68
|
+
lastCheck: new Date(),
|
|
69
|
+
secondsToWait: Math.round(20 + 10 * Math.random()),
|
|
70
|
+
numEmptyReceives: 0 + emptyReceive
|
|
71
|
+
}, lastCheck = _a.lastCheck, secondsToWait = _a.secondsToWait, numEmptyReceives = _a.numEmptyReceives;
|
|
72
|
+
if (emptyReceive) {
|
|
73
|
+
var now = new Date();
|
|
74
|
+
var secondsElapsed = lastCheck - now;
|
|
75
|
+
var minWait = 10;
|
|
76
|
+
var maxWait = 600;
|
|
77
|
+
var baseSeconds = Math.pow(numEmptyReceives, 2) * 20;
|
|
78
|
+
var jitterSeconds = Math.round((Math.random() - 0.5) * baseSeconds);
|
|
79
|
+
var newSecondsToWait = Math.max(minWait, Math.min(maxWait, baseSeconds + jitterSeconds));
|
|
80
|
+
var newEntry = { lastCheck: now, secondsToWait: newSecondsToWait, numEmptyReceives: numEmptyReceives + 1 };
|
|
81
|
+
this.icehouse[qrl] = newEntry;
|
|
82
|
+
if (this.opt.verbose) {
|
|
83
|
+
console.error(chalk_1.default.blue('Sending queue to icehouse'), qrl, chalk_1.default.blue('for'), newSecondsToWait, chalk_1.default.blue('seconds'));
|
|
84
|
+
}
|
|
85
|
+
debug({ foundEntry: foundEntry, newEntry: newEntry, lastCheck: lastCheck, secondsToWait: secondsToWait, now: now, secondsElapsed: secondsElapsed, maxWait: maxWait, minWait: minWait, baseSeconds: baseSeconds, jitterSeconds: jitterSeconds });
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
delete this.icehouse[qrl];
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
// Returns true if the queue should be kept in the icehouse
|
|
92
|
+
QueueManager.prototype.keepInIcehouse = function (qrl, now) {
|
|
93
|
+
if (this.icehouse[qrl]) {
|
|
94
|
+
var _a = this.icehouse[qrl], lastCheck = _a.lastCheck, secondsToWait = _a.secondsToWait;
|
|
95
|
+
var secondsElapsed = Math.round((now - lastCheck) / 1000);
|
|
96
|
+
debug({ icehouseCheck: { qrl: qrl, lastCheck: lastCheck, secondsToWait: secondsToWait, secondsElapsed: secondsElapsed } });
|
|
97
|
+
var letOut = secondsElapsed > secondsToWait;
|
|
98
|
+
if (letOut && this.opt.verbose) {
|
|
99
|
+
console.error(chalk_1.default.blue('Coming out of icehouse:'), qrl);
|
|
100
|
+
}
|
|
101
|
+
return !letOut;
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
};
|
|
63
107
|
QueueManager.prototype.resolveQueues = function () {
|
|
64
108
|
return __awaiter(this, void 0, void 0, function () {
|
|
65
|
-
var qnames, pairs, activePairs;
|
|
109
|
+
var qnames, pairs, now, filteredPairs, activePairs;
|
|
66
110
|
var _this = this;
|
|
67
111
|
return __generator(this, function (_a) {
|
|
68
112
|
switch (_a.label) {
|
|
69
113
|
case 0:
|
|
114
|
+
clearTimeout(this.resolveTimeout);
|
|
70
115
|
if (this.shutdownRequested)
|
|
71
116
|
return [2 /*return*/];
|
|
72
|
-
// Start processing
|
|
73
|
-
if (this.opt.verbose)
|
|
74
|
-
console.error(chalk_1.default.blue('Resolving queues: ') + this.queues.join(' '));
|
|
75
117
|
qnames = this.queues.map(function (queue) { return (0, qrlCache_js_1.normalizeQueueName)(queue, _this.opt); });
|
|
76
118
|
return [4 /*yield*/, (0, qrlCache_js_1.getQnameUrlPairs)(qnames, this.opt)];
|
|
77
119
|
case 1:
|
|
78
120
|
pairs = _a.sent();
|
|
121
|
+
if (this.opt.verbose)
|
|
122
|
+
console.error(chalk_1.default.blue('Resolving queues:'));
|
|
79
123
|
if (this.shutdownRequested)
|
|
80
124
|
return [2 /*return*/];
|
|
125
|
+
now = new Date();
|
|
126
|
+
filteredPairs = pairs
|
|
127
|
+
// first failed
|
|
128
|
+
.filter(function (_a) {
|
|
129
|
+
var qname = _a.qname, qrl = _a.qrl;
|
|
130
|
+
var suf = _this.opt.failSuffix + (_this.opt.fifo ? '.fifo' : '');
|
|
131
|
+
var isFailQueue = qname.slice(-suf.length) === suf;
|
|
132
|
+
return _this.opt.includeFailed ? true : !isFailQueue;
|
|
133
|
+
})
|
|
134
|
+
// first fifo
|
|
135
|
+
.filter(function (_a) {
|
|
136
|
+
var qname = _a.qname, qrl = _a.qrl;
|
|
137
|
+
var isFifo = qname.endsWith('.fifo');
|
|
138
|
+
return _this.opt.fifo ? isFifo : !isFifo;
|
|
139
|
+
})
|
|
140
|
+
// then icehouse
|
|
141
|
+
.filter(function (_a) {
|
|
142
|
+
var qname = _a.qname, qrl = _a.qrl;
|
|
143
|
+
return !_this.keepInIcehouse(qrl, now);
|
|
144
|
+
});
|
|
81
145
|
activePairs = [];
|
|
82
146
|
if (!this.opt.activeOnly) return [3 /*break*/, 3];
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
147
|
+
if (this.opt.verbose) {
|
|
148
|
+
console.error(chalk_1.default.blue(' checking active only'));
|
|
149
|
+
}
|
|
150
|
+
return [4 /*yield*/, Promise.all(filteredPairs.map(function (_a) {
|
|
151
|
+
var qname = _a.qname, qrl = _a.qrl;
|
|
152
|
+
return __awaiter(_this, void 0, void 0, function () {
|
|
153
|
+
var idle;
|
|
154
|
+
return __generator(this, function (_b) {
|
|
155
|
+
switch (_b.label) {
|
|
156
|
+
case 0: return [4 /*yield*/, (0, idleQueues_js_1.cheapIdleCheck)(qname, qrl, this.opt)];
|
|
157
|
+
case 1:
|
|
158
|
+
idle = (_b.sent()).result.idle;
|
|
159
|
+
debug({ idle: idle, qname: qname });
|
|
160
|
+
if (!idle)
|
|
161
|
+
activePairs.push({ qname: qname, qrl: qrl });
|
|
162
|
+
return [2 /*return*/];
|
|
163
|
+
}
|
|
164
|
+
});
|
|
95
165
|
});
|
|
96
|
-
})
|
|
166
|
+
}))];
|
|
97
167
|
case 2:
|
|
98
168
|
_a.sent();
|
|
99
169
|
_a.label = 3;
|
|
100
170
|
case 3:
|
|
101
171
|
if (this.shutdownRequested)
|
|
102
172
|
return [2 /*return*/];
|
|
103
|
-
// Finished resolving
|
|
104
|
-
if (this.opt.verbose) {
|
|
105
|
-
console.error(chalk_1.default.blue(' done'));
|
|
106
|
-
console.error();
|
|
107
|
-
}
|
|
108
173
|
// Figure out which queues we want to listen on, choosing between active and
|
|
109
174
|
// all, filtering out failed queues if the user wants that
|
|
110
|
-
this.selectedPairs = (this.opt.activeOnly ? activePairs :
|
|
111
|
-
.filter(function (_a) {
|
|
112
|
-
var qname = _a.qname;
|
|
113
|
-
var suf = _this.opt.failSuffix + (_this.opt.fifo ? '.fifo' : '');
|
|
114
|
-
var isFailQueue = qname.slice(-suf.length) === suf;
|
|
115
|
-
var shouldInclude = _this.opt.includeFailed ? true : !isFailQueue;
|
|
116
|
-
return shouldInclude;
|
|
117
|
-
});
|
|
175
|
+
this.selectedPairs = (this.opt.activeOnly ? activePairs : filteredPairs);
|
|
118
176
|
// Randomize order
|
|
119
177
|
this.selectedPairs.sort(function () { return 0.5 - Math.random(); });
|
|
178
|
+
if (this.opt.verbose)
|
|
179
|
+
console.error(chalk_1.default.blue(' selected:\n ') + this.selectedPairs.map(function (_a) {
|
|
180
|
+
var qname = _a.qname;
|
|
181
|
+
return qname;
|
|
182
|
+
}).join('\n '));
|
|
120
183
|
debug('selectedPairs', this.selectedPairs);
|
|
184
|
+
// Finished resolving
|
|
185
|
+
if (this.opt.verbose) {
|
|
186
|
+
console.error(chalk_1.default.blue(' done'));
|
|
187
|
+
console.error();
|
|
188
|
+
}
|
|
121
189
|
if (this.opt.verbose) {
|
|
122
190
|
console.error(chalk_1.default.blue('Will resolve queues again in ' + this.resolveSeconds + ' seconds'));
|
|
123
191
|
}
|
|
124
|
-
this.resolveTimeout = setTimeout(function () {
|
|
192
|
+
this.resolveTimeout = setTimeout(function () {
|
|
193
|
+
_this.resolvePromise = _this.resolveQueues();
|
|
194
|
+
}, this.resolveSeconds * 1000);
|
|
125
195
|
return [2 /*return*/];
|
|
126
196
|
}
|
|
127
197
|
});
|
|
@@ -134,11 +204,27 @@ var QueueManager = /** @class */ (function () {
|
|
|
134
204
|
return pair;
|
|
135
205
|
};
|
|
136
206
|
QueueManager.prototype.getPairs = function () {
|
|
137
|
-
|
|
207
|
+
var _this = this;
|
|
208
|
+
var now = new Date();
|
|
209
|
+
return this.selectedPairs.filter(function (_a) {
|
|
210
|
+
var qname = _a.qname, qrl = _a.qrl;
|
|
211
|
+
return !_this.keepInIcehouse(qrl, now);
|
|
212
|
+
});
|
|
138
213
|
};
|
|
139
214
|
QueueManager.prototype.shutdown = function () {
|
|
140
|
-
|
|
141
|
-
|
|
215
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
216
|
+
return __generator(this, function (_a) {
|
|
217
|
+
switch (_a.label) {
|
|
218
|
+
case 0:
|
|
219
|
+
this.shutdownRequested = true;
|
|
220
|
+
clearTimeout(this.resolveTimeout);
|
|
221
|
+
return [4 /*yield*/, this.resolvePromise];
|
|
222
|
+
case 1:
|
|
223
|
+
_a.sent();
|
|
224
|
+
return [2 /*return*/];
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
});
|
|
142
228
|
};
|
|
143
229
|
return QueueManager;
|
|
144
230
|
}());
|
|
@@ -6,59 +6,43 @@
|
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
7
|
exports.SystemMonitor = void 0;
|
|
8
8
|
var SystemMonitor = /** @class */ (function () {
|
|
9
|
-
function SystemMonitor(
|
|
10
|
-
if (
|
|
11
|
-
|
|
12
|
-
this.opt = opt;
|
|
13
|
-
this.smoothingFactor = smoothingFactor;
|
|
9
|
+
function SystemMonitor(reportCallback, reportSeconds) {
|
|
10
|
+
if (reportSeconds === void 0) { reportSeconds = 1; }
|
|
11
|
+
this.reportCallback = reportCallback || console.log;
|
|
14
12
|
this.reportSeconds = reportSeconds;
|
|
15
|
-
this.measurements =
|
|
16
|
-
|
|
17
|
-
setImmediate: []
|
|
18
|
-
};
|
|
19
|
-
this.timeouts = {
|
|
20
|
-
setTimeout: undefined,
|
|
21
|
-
setImmediate: undefined,
|
|
22
|
-
reportLatency: undefined
|
|
23
|
-
};
|
|
24
|
-
this.measureLatencySetTimeout();
|
|
13
|
+
this.measurements = [];
|
|
14
|
+
this.measure();
|
|
25
15
|
this.reportLatency();
|
|
26
16
|
}
|
|
27
|
-
SystemMonitor.prototype.
|
|
17
|
+
SystemMonitor.prototype.measure = function () {
|
|
28
18
|
var _this = this;
|
|
19
|
+
clearTimeout(this.measureTimeout);
|
|
29
20
|
var start = new Date();
|
|
30
|
-
this.
|
|
21
|
+
this.measureTimeout = setTimeout(function () {
|
|
31
22
|
var latency = new Date() - start;
|
|
32
|
-
_this.measurements.
|
|
33
|
-
if (_this.measurements.
|
|
34
|
-
_this.measurements.
|
|
35
|
-
_this.
|
|
23
|
+
_this.measurements.push(latency);
|
|
24
|
+
if (_this.measurements.length > 1000)
|
|
25
|
+
_this.measurements.shift();
|
|
26
|
+
_this.measure();
|
|
36
27
|
});
|
|
37
28
|
};
|
|
38
29
|
SystemMonitor.prototype.getLatency = function () {
|
|
39
|
-
|
|
40
|
-
for (var k in this.measurements) {
|
|
41
|
-
var values = this.measurements[k];
|
|
42
|
-
results[k] = values.length ? values.reduce(function (a, b) { return a + b; }, 0) / values.length : 0;
|
|
43
|
-
}
|
|
44
|
-
return results;
|
|
30
|
+
return this.measurements.length ? this.measurements.reduce(function (a, b) { return a + b; }, 0) / this.measurements.length : 0;
|
|
45
31
|
};
|
|
46
32
|
SystemMonitor.prototype.reportLatency = function () {
|
|
47
33
|
var _this = this;
|
|
48
|
-
this.
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
34
|
+
clearTimeout(this.reportTimeout);
|
|
35
|
+
this.reportTimeout = setTimeout(function () {
|
|
36
|
+
var latency = _this.getLatency();
|
|
37
|
+
// console.log({ latency })
|
|
38
|
+
if (_this.reportCallback)
|
|
39
|
+
_this.reportCallback(latency);
|
|
55
40
|
_this.reportLatency();
|
|
56
41
|
}, this.reportSeconds * 1000);
|
|
57
42
|
};
|
|
58
43
|
SystemMonitor.prototype.shutdown = function () {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
clearTimeout(this.timeouts[k]);
|
|
44
|
+
clearTimeout(this.measureTimeout);
|
|
45
|
+
clearTimeout(this.reportTimeout);
|
|
62
46
|
};
|
|
63
47
|
return SystemMonitor;
|
|
64
48
|
}());
|
package/package.json
CHANGED
package/src/consumer.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Consumer implementation.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import { ReceiveMessageCommand } from '@aws-sdk/client-sqs'
|
|
5
|
+
import { ReceiveMessageCommand, QueueDoesNotExist } from '@aws-sdk/client-sqs'
|
|
6
6
|
import chalk from 'chalk'
|
|
7
7
|
import Debug from 'debug'
|
|
8
8
|
|
|
@@ -18,12 +18,12 @@ const debug = Debug('qdone:consumer')
|
|
|
18
18
|
let shutdownRequested = false
|
|
19
19
|
const shutdownCallbacks = []
|
|
20
20
|
|
|
21
|
-
export function requestShutdown () {
|
|
21
|
+
export async function requestShutdown () {
|
|
22
22
|
debug('requestShutdown')
|
|
23
23
|
shutdownRequested = true
|
|
24
24
|
for (const callback of shutdownCallbacks) {
|
|
25
25
|
debug('callback', callback)
|
|
26
|
-
callback()
|
|
26
|
+
await callback()
|
|
27
27
|
// try { callback() } catch (e) { }
|
|
28
28
|
}
|
|
29
29
|
debug('requestShutdown done')
|
|
@@ -35,7 +35,7 @@ export async function getMessages (qrl, opt, maxMessages) {
|
|
|
35
35
|
MaxNumberOfMessages: maxMessages,
|
|
36
36
|
MessageAttributeNames: ['All'],
|
|
37
37
|
QueueUrl: qrl,
|
|
38
|
-
VisibilityTimeout:
|
|
38
|
+
VisibilityTimeout: 60,
|
|
39
39
|
WaitTimeSeconds: opt.waitTime
|
|
40
40
|
}
|
|
41
41
|
const response = await getSQSClient().send(new ReceiveMessageCommand(params))
|
|
@@ -47,19 +47,21 @@ export async function getMessages (qrl, opt, maxMessages) {
|
|
|
47
47
|
// Consumer
|
|
48
48
|
//
|
|
49
49
|
export async function processMessages (queues, callback, options) {
|
|
50
|
+
debug({ options })
|
|
50
51
|
const opt = getOptionsWithDefaults(options)
|
|
51
|
-
debug('processMessages', { queues, callback, options, opt })
|
|
52
|
+
debug('processMessages', { queues, callback, options, opt, argv: process.argv })
|
|
52
53
|
|
|
53
|
-
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
queueManager.shutdown()
|
|
61
|
-
jobExecutor.shutdown()
|
|
54
|
+
let lastLatency = 10
|
|
55
|
+
const systemMonitor = new SystemMonitor(latency => {
|
|
56
|
+
const percentDifference = 100 * Math.abs(lastLatency - latency) / lastLatency
|
|
57
|
+
if (percentDifference > 10 && opt.verbose) {
|
|
58
|
+
console.error(chalk.blue('Latency:', Math.round(latency), 'ms'))
|
|
59
|
+
}
|
|
60
|
+
lastLatency = latency
|
|
62
61
|
})
|
|
62
|
+
const jobExecutor = new JobExecutor(opt)
|
|
63
|
+
const queueManager = new QueueManager(opt, queues, 60)
|
|
64
|
+
// debug({ systemMonitor, jobExecutor, queueManager })
|
|
63
65
|
|
|
64
66
|
// This delay function keeps a timeout reference around so it can be
|
|
65
67
|
// cancelled at shutdown
|
|
@@ -68,31 +70,58 @@ export async function processMessages (queues, callback, options) {
|
|
|
68
70
|
delayTimeout = setTimeout(resolve, ms)
|
|
69
71
|
})
|
|
70
72
|
|
|
73
|
+
shutdownCallbacks.push(async () => {
|
|
74
|
+
clearTimeout(delayTimeout)
|
|
75
|
+
await queueManager.shutdown()
|
|
76
|
+
debug({ queueManager: 'done' })
|
|
77
|
+
await jobExecutor.shutdown()
|
|
78
|
+
debug({ jobExecutor: 'done' })
|
|
79
|
+
await systemMonitor.shutdown()
|
|
80
|
+
debug({ systemMonitor: 'done' })
|
|
81
|
+
})
|
|
82
|
+
|
|
71
83
|
// Keep track of how many messages could be returned from each queue
|
|
72
84
|
const activeQrls = new Set()
|
|
73
85
|
let maxReturnCount = 0
|
|
74
86
|
const listen = async (qname, qrl, maxMessages) => {
|
|
75
87
|
activeQrls.add(qrl)
|
|
76
88
|
maxReturnCount += maxMessages
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
89
|
+
try {
|
|
90
|
+
const messages = await getMessages(qrl, opt, maxMessages)
|
|
91
|
+
if (messages.length) {
|
|
92
|
+
for (const message of messages) {
|
|
93
|
+
jobExecutor.executeJob(message, callback, qname, qrl)
|
|
94
|
+
}
|
|
95
|
+
queueManager.updateIcehouse(qrl, false)
|
|
96
|
+
} else {
|
|
97
|
+
// If we didn't get any, update the icehouse so we can back off
|
|
98
|
+
queueManager.updateIcehouse(qrl, true)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Max job accounting
|
|
102
|
+
maxReturnCount -= maxMessages
|
|
103
|
+
activeQrls.delete(qrl)
|
|
104
|
+
} catch (e) {
|
|
105
|
+
// If the queue has been cleaned up, we should back off anyway
|
|
106
|
+
if (e instanceof QueueDoesNotExist) {
|
|
107
|
+
queueManager.updateIcehouse(qrl, true)
|
|
108
|
+
} else {
|
|
109
|
+
throw e
|
|
110
|
+
}
|
|
80
111
|
}
|
|
81
|
-
maxReturnCount -= maxMessages
|
|
82
|
-
activeQrls.delete(qrl)
|
|
83
112
|
}
|
|
84
113
|
|
|
85
114
|
while (!shutdownRequested) { // eslint-disable-line
|
|
86
115
|
// Figure out how we are running
|
|
87
|
-
const allowedJobs = opt.maxConcurrentJobs - jobExecutor.activeJobCount() - maxReturnCount
|
|
116
|
+
const allowedJobs = Math.max(0, opt.maxConcurrentJobs - jobExecutor.activeJobCount() - maxReturnCount)
|
|
88
117
|
const maxLatency = 100
|
|
89
|
-
const latency = systemMonitor.getLatency()
|
|
118
|
+
const latency = systemMonitor.getLatency() || 10
|
|
90
119
|
const latencyFactor = 1 - Math.abs(Math.min(latency / maxLatency, 1)) // 0 if latency is at max, 1 if latency 0
|
|
91
120
|
const targetJobs = Math.round(allowedJobs * latencyFactor)
|
|
92
|
-
debug({ allowedJobs, maxLatency, latency, latencyFactor, targetJobs, activeQrls })
|
|
93
|
-
|
|
94
121
|
let jobsLeft = targetJobs
|
|
122
|
+
debug({ jobCount: jobExecutor.activeJobCount(), maxReturnCount, allowedJobs, maxLatency, latency, latencyFactor, targetJobs, activeQrls })
|
|
95
123
|
for (const { qname, qrl } of queueManager.getPairs()) {
|
|
124
|
+
debug({ evaluating: { qname, qrl, jobsLeft, activeQrlsHasQrl: activeQrls.has(qrl) } })
|
|
96
125
|
if (jobsLeft <= 0 || activeQrls.has(qrl)) continue
|
|
97
126
|
const maxMessages = Math.min(10, jobsLeft)
|
|
98
127
|
listen(qname, qrl, maxMessages)
|
package/src/defaults.js
CHANGED
|
@@ -44,6 +44,12 @@ export const defaults = Object.freeze({
|
|
|
44
44
|
unpair: false
|
|
45
45
|
})
|
|
46
46
|
|
|
47
|
+
function validateInteger (opt, name) {
|
|
48
|
+
const parsed = parseInt(opt[name], 10)
|
|
49
|
+
if (isNaN(parsed)) throw new Error(`${name} needs to be an integer.`)
|
|
50
|
+
return parsed
|
|
51
|
+
}
|
|
52
|
+
|
|
47
53
|
/**
|
|
48
54
|
* This function should be called by each exposed API entry point on the
|
|
49
55
|
* options passed in from the caller. It supports options named in camelCase
|
|
@@ -101,9 +107,22 @@ export function getOptionsWithDefaults (options) {
|
|
|
101
107
|
delete: options.delete || defaults.delete,
|
|
102
108
|
unpair: options.delete || defaults.unpair
|
|
103
109
|
}
|
|
110
|
+
|
|
111
|
+
// Setting this env here means we don't have to in AWS SDK constructors
|
|
104
112
|
process.env.AWS_REGION = opt.region
|
|
105
113
|
|
|
106
|
-
//
|
|
114
|
+
// Validation
|
|
115
|
+
opt.cacheTtlSeconds = validateInteger(opt, 'cacheTtlSeconds')
|
|
116
|
+
opt.messageRetentionPeriod = validateInteger(opt, 'messageRetentionPeriod')
|
|
117
|
+
opt.delay = validateInteger(opt, 'delay')
|
|
118
|
+
opt.sendRetries = validateInteger(opt, 'sendRetries')
|
|
119
|
+
opt.failDelay = validateInteger(opt, 'failDelay')
|
|
120
|
+
opt.dlqAfter = validateInteger(opt, 'dlqAfter')
|
|
121
|
+
opt.waitTime = validateInteger(opt, 'waitTime')
|
|
122
|
+
opt.killAfter = validateInteger(opt, 'killAfter')
|
|
123
|
+
opt.maxConcurrentJobs = validateInteger(opt, 'maxConcurrentJobs')
|
|
124
|
+
opt.idleFor = validateInteger(opt, 'idleFor')
|
|
125
|
+
|
|
107
126
|
return opt
|
|
108
127
|
}
|
|
109
128
|
|
package/src/idleQueues.js
CHANGED
|
@@ -40,7 +40,7 @@ export async function _cheapIdleCheck (qname, qrl, opt) {
|
|
|
40
40
|
const client = getSQSClient()
|
|
41
41
|
const cmd = new GetQueueAttributesCommand({ AttributeNames: attributeNames, QueueUrl: qrl })
|
|
42
42
|
const data = await client.send(cmd)
|
|
43
|
-
|
|
43
|
+
debug('data', data)
|
|
44
44
|
const result = data.Attributes
|
|
45
45
|
result.queue = qname.slice(opt.prefix.length)
|
|
46
46
|
// We are idle if all the messages attributes are zero
|