qdone 2.0.53-alpha → 2.0.55-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 +22 -7
- package/commonjs/src/idleQueues.js +1 -1
- package/commonjs/src/scheduler/jobExecutor.js +3 -1
- package/commonjs/src/scheduler/systemMonitor.js +1 -1
- package/package.json +1 -1
- package/src/cli.js +2 -8
- package/src/consumer.js +21 -8
- package/src/idleQueues.js +2 -2
- package/src/scheduler/jobExecutor.js +3 -1
- package/src/scheduler/systemMonitor.js +2 -2
package/commonjs/src/consumer.js
CHANGED
|
@@ -80,19 +80,27 @@ async function processMessages(queues, callback, options) {
|
|
|
80
80
|
debug({ systemMonitor: 'done' });
|
|
81
81
|
});
|
|
82
82
|
// Keep track of how many messages could be returned from each queue
|
|
83
|
-
const activeQrls = new
|
|
83
|
+
const activeQrls = new Map();
|
|
84
|
+
const listeningQrls = new Set();
|
|
84
85
|
let maxReturnCount = 0;
|
|
85
86
|
const listen = async (qname, qrl, maxMessages) => {
|
|
86
87
|
if (opt.verbose) {
|
|
87
88
|
console.error(chalk_1.default.blue('Listening on: '), qname);
|
|
88
89
|
}
|
|
89
|
-
activeQrls.add(qrl);
|
|
90
90
|
maxReturnCount += maxMessages;
|
|
91
91
|
try {
|
|
92
|
+
listeningQrls.add(qrl);
|
|
92
93
|
const messages = await getMessages(qrl, opt, maxMessages);
|
|
94
|
+
listeningQrls.delete(qrl);
|
|
93
95
|
if (!shutdownRequested) {
|
|
94
96
|
if (messages.length) {
|
|
95
|
-
|
|
97
|
+
activeQrls.set(qrl, (activeQrls.get(qrl) || 0) + 1);
|
|
98
|
+
await jobExecutor.executeJobs(messages, callback, qname, qrl);
|
|
99
|
+
const count = activeQrls.get(qrl) - 1;
|
|
100
|
+
if (count)
|
|
101
|
+
activeQrls.set(qrl, count);
|
|
102
|
+
else
|
|
103
|
+
activeQrls.delete(qrl);
|
|
96
104
|
queueManager.updateIcehouse(qrl, false);
|
|
97
105
|
}
|
|
98
106
|
else {
|
|
@@ -102,7 +110,6 @@ async function processMessages(queues, callback, options) {
|
|
|
102
110
|
}
|
|
103
111
|
// Max job accounting
|
|
104
112
|
maxReturnCount -= maxMessages;
|
|
105
|
-
activeQrls.delete(qrl);
|
|
106
113
|
}
|
|
107
114
|
catch (e) {
|
|
108
115
|
// If the queue has been cleaned up, we should back off anyway
|
|
@@ -114,6 +121,14 @@ async function processMessages(queues, callback, options) {
|
|
|
114
121
|
}
|
|
115
122
|
}
|
|
116
123
|
};
|
|
124
|
+
if (opt.verbose) {
|
|
125
|
+
function printUrls() {
|
|
126
|
+
console.error({ activeQrls, listeningQrls });
|
|
127
|
+
if (!shutdownRequested)
|
|
128
|
+
setTimeout(printUrls, 2000);
|
|
129
|
+
}
|
|
130
|
+
printUrls();
|
|
131
|
+
}
|
|
117
132
|
while (!shutdownRequested) { // eslint-disable-line
|
|
118
133
|
// Figure out how we are running
|
|
119
134
|
const runningJobs = jobExecutor.runningJobCount();
|
|
@@ -137,21 +152,21 @@ async function processMessages(queues, callback, options) {
|
|
|
137
152
|
const targetJobs = Math.round(allowedJobs * overallFactor);
|
|
138
153
|
let jobsLeft = targetJobs;
|
|
139
154
|
if (opt.verbose) {
|
|
140
|
-
console.error({ maxConcurrentJobs: opt.maxConcurrentJobs, maxReturnCount, runningJobs, allowedJobs, maxLatency, latencyFactor, freememFactor, loadFactor, overallFactor, targetJobs
|
|
155
|
+
console.error({ maxConcurrentJobs: opt.maxConcurrentJobs, maxReturnCount, runningJobs, allowedJobs, maxLatency, latencyFactor, freememFactor, loadFactor, overallFactor, targetJobs });
|
|
141
156
|
}
|
|
142
157
|
for (const { qname, qrl } of queueManager.getPairs()) {
|
|
143
158
|
// const qcount = jobExecutor.runningJobCountForQueue(qname)
|
|
144
159
|
// console.log({ evaluating: { qname, qrl, qcount, jobsLeft, activeQrlsHasQrl: activeQrls.has(qrl) } })
|
|
145
160
|
if (jobsLeft <= 0)
|
|
146
161
|
break;
|
|
147
|
-
if (
|
|
162
|
+
if (listeningQrls.has(qrl))
|
|
148
163
|
continue;
|
|
149
164
|
const maxMessages = Math.min(10, jobsLeft);
|
|
150
165
|
listen(qname, qrl, maxMessages);
|
|
151
166
|
jobsLeft -= maxMessages;
|
|
152
167
|
// debug({ listenedTo: { qname, maxMessages, jobsLeft } })
|
|
153
168
|
}
|
|
154
|
-
await delay(
|
|
169
|
+
await delay(300);
|
|
155
170
|
}
|
|
156
171
|
debug('after all');
|
|
157
172
|
}
|
|
@@ -137,7 +137,7 @@ async function checkIdle(qname, qrl, opt) {
|
|
|
137
137
|
if (cheapResult.idle === false || cheapResult.exists === false) {
|
|
138
138
|
return {
|
|
139
139
|
queue: qname.slice(opt.prefix.length),
|
|
140
|
-
cheap: cheapResult,
|
|
140
|
+
cheap: { SQS, result: cheapResult },
|
|
141
141
|
idle: cheapResult.idle,
|
|
142
142
|
exists: cheapResult.exists,
|
|
143
143
|
apiCalls: { SQS, CloudWatch: 0 }
|
|
@@ -363,6 +363,7 @@ class JobExecutor {
|
|
|
363
363
|
// Begin tracking jobs
|
|
364
364
|
const jobs = messages.map(message => this.addJob(message, callback, qname, qrl));
|
|
365
365
|
const isFifo = qrl.endsWith('.fifo');
|
|
366
|
+
const runningJobs = [];
|
|
366
367
|
// console.log(jobs)
|
|
367
368
|
// Begin executing
|
|
368
369
|
for (const [job, i] of jobs.map((job, i) => [job, i])) {
|
|
@@ -374,8 +375,9 @@ class JobExecutor {
|
|
|
374
375
|
if (nextJobIsSerial)
|
|
375
376
|
await this.runJob(job);
|
|
376
377
|
else
|
|
377
|
-
this.runJob(job);
|
|
378
|
+
runningJobs.push(this.runJob(job));
|
|
378
379
|
}
|
|
380
|
+
await Promise.all(runningJobs);
|
|
379
381
|
}
|
|
380
382
|
}
|
|
381
383
|
exports.JobExecutor = JobExecutor;
|
|
@@ -71,7 +71,7 @@ class SystemMonitor {
|
|
|
71
71
|
* second is better to reduce latency of detecting the change.
|
|
72
72
|
*/
|
|
73
73
|
measureLoad() {
|
|
74
|
-
const [newLoad
|
|
74
|
+
const [newLoad] = os_1.default.loadavg();
|
|
75
75
|
const previousLoad = this.oneMinuteLoad;
|
|
76
76
|
if (previousLoad !== newLoad) {
|
|
77
77
|
const e = 1884 / 2048; // see include/linux/sched/loadavg.h
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -451,19 +451,14 @@ export async function idleQueues (argv, testHook) {
|
|
|
451
451
|
{
|
|
452
452
|
content: [
|
|
453
453
|
{ count: '1 + q + i', desc: 'q: number of queues in pattern\ni: number of idle queues' },
|
|
454
|
-
{ context: 'with --delete options', count: '1 + q + 3i', desc: 'q: number of queues in pattern\ni: number of idle queues' }
|
|
455
|
-
{ context: 'with --unpair option', count: '1 + q', desc: 'q: number of queues in pattern' },
|
|
456
|
-
{ context: 'with --unpair and --delete options', count: '1 + q + i', desc: 'q: number of queues in pattern\ni: number of idle queues' },
|
|
457
|
-
{ desc: 'NOTE: the --unpair option not cheaper if you include fail queues, because it doubles q.' }
|
|
454
|
+
{ context: 'with --delete options', count: '1 + q + 3i', desc: 'q: number of queues in pattern\ni: number of idle queues' }
|
|
458
455
|
],
|
|
459
456
|
long: true
|
|
460
457
|
},
|
|
461
458
|
{ content: 'CloudWatch API Call Complexity', raw: true, long: true },
|
|
462
459
|
{
|
|
463
460
|
content: [
|
|
464
|
-
{ count: 'min: 0 (if queue and fail queue have waiting messages)\nmax: 12q\nexpected (approximate observed): 0.5q + 12i', desc: 'q: number of queues in pattern\ni: number of idle queues' }
|
|
465
|
-
{ context: 'with --unpair option', count: 'min: 0 (if queue has waiting messages)\nmax: 6q\nexpected (approximate observed): q + 6i', desc: 'q: number of queues in pattern\ni: number of idle queues' },
|
|
466
|
-
{ desc: 'NOTE: the --unpair option not cheaper if you include fail queues, because it doubles q.' }
|
|
461
|
+
{ count: 'min: 0 (if queue and fail queue have waiting messages)\nmax: 12q\nexpected (approximate observed): 0.5q + 12i', desc: 'q: number of queues in pattern\ni: number of idle queues' }
|
|
467
462
|
],
|
|
468
463
|
long: true
|
|
469
464
|
},
|
|
@@ -479,7 +474,6 @@ export async function idleQueues (argv, testHook) {
|
|
|
479
474
|
debug('idleQueues options', options)
|
|
480
475
|
if (options.help) return Promise.resolve(console.log(getUsage(usageSections)))
|
|
481
476
|
if (!options._unknown || options._unknown.length === 0) throw new UsageError('idle-queues requres one or more <queue> arguments')
|
|
482
|
-
if (options['include-failed'] && !options.unpair) throw new UsageError('--include-failed should be used with --unpair')
|
|
483
477
|
if (options['idle-for'] < 5) throw new UsageError('--idle-for must be at least 5 minutes (CloudWatch limitation)')
|
|
484
478
|
queues = options._unknown
|
|
485
479
|
debug('queues', queues)
|
package/src/consumer.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Consumer implementation.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import { freemem, totalmem,
|
|
5
|
+
import { freemem, totalmem, cpus } from 'os'
|
|
6
6
|
import { ReceiveMessageCommand, QueueDoesNotExist } from '@aws-sdk/client-sqs'
|
|
7
7
|
import chalk from 'chalk'
|
|
8
8
|
import Debug from 'debug'
|
|
@@ -83,20 +83,26 @@ export async function processMessages (queues, callback, options) {
|
|
|
83
83
|
})
|
|
84
84
|
|
|
85
85
|
// Keep track of how many messages could be returned from each queue
|
|
86
|
-
const activeQrls = new
|
|
86
|
+
const activeQrls = new Map()
|
|
87
|
+
const listeningQrls = new Set()
|
|
87
88
|
let maxReturnCount = 0
|
|
88
89
|
const listen = async (qname, qrl, maxMessages) => {
|
|
89
90
|
if (opt.verbose) {
|
|
90
91
|
console.error(chalk.blue('Listening on: '), qname)
|
|
91
92
|
}
|
|
92
|
-
activeQrls.add(qrl)
|
|
93
93
|
maxReturnCount += maxMessages
|
|
94
94
|
try {
|
|
95
|
+
listeningQrls.add(qrl)
|
|
95
96
|
const messages = await getMessages(qrl, opt, maxMessages)
|
|
97
|
+
listeningQrls.delete(qrl)
|
|
96
98
|
|
|
97
99
|
if (!shutdownRequested) {
|
|
98
100
|
if (messages.length) {
|
|
99
|
-
|
|
101
|
+
activeQrls.set(qrl, (activeQrls.get(qrl) || 0) + 1)
|
|
102
|
+
await jobExecutor.executeJobs(messages, callback, qname, qrl)
|
|
103
|
+
const count = activeQrls.get(qrl) - 1
|
|
104
|
+
if (count) activeQrls.set(qrl, count)
|
|
105
|
+
else activeQrls.delete(qrl)
|
|
100
106
|
queueManager.updateIcehouse(qrl, false)
|
|
101
107
|
} else {
|
|
102
108
|
// If we didn't get any, update the icehouse so we can back off
|
|
@@ -106,7 +112,6 @@ export async function processMessages (queues, callback, options) {
|
|
|
106
112
|
|
|
107
113
|
// Max job accounting
|
|
108
114
|
maxReturnCount -= maxMessages
|
|
109
|
-
activeQrls.delete(qrl)
|
|
110
115
|
} catch (e) {
|
|
111
116
|
// If the queue has been cleaned up, we should back off anyway
|
|
112
117
|
if (e instanceof QueueDoesNotExist) {
|
|
@@ -117,6 +122,14 @@ export async function processMessages (queues, callback, options) {
|
|
|
117
122
|
}
|
|
118
123
|
}
|
|
119
124
|
|
|
125
|
+
if (opt.verbose) {
|
|
126
|
+
function printUrls () {
|
|
127
|
+
console.error({ activeQrls, listeningQrls })
|
|
128
|
+
if (!shutdownRequested) setTimeout(printUrls, 2000)
|
|
129
|
+
}
|
|
130
|
+
printUrls()
|
|
131
|
+
}
|
|
132
|
+
|
|
120
133
|
while (!shutdownRequested) { // eslint-disable-line
|
|
121
134
|
// Figure out how we are running
|
|
122
135
|
const runningJobs = jobExecutor.runningJobCount()
|
|
@@ -145,19 +158,19 @@ export async function processMessages (queues, callback, options) {
|
|
|
145
158
|
let jobsLeft = targetJobs
|
|
146
159
|
|
|
147
160
|
if (opt.verbose) {
|
|
148
|
-
console.error({ maxConcurrentJobs: opt.maxConcurrentJobs, maxReturnCount, runningJobs, allowedJobs, maxLatency, latencyFactor, freememFactor, loadFactor, overallFactor, targetJobs
|
|
161
|
+
console.error({ maxConcurrentJobs: opt.maxConcurrentJobs, maxReturnCount, runningJobs, allowedJobs, maxLatency, latencyFactor, freememFactor, loadFactor, overallFactor, targetJobs })
|
|
149
162
|
}
|
|
150
163
|
for (const { qname, qrl } of queueManager.getPairs()) {
|
|
151
164
|
// const qcount = jobExecutor.runningJobCountForQueue(qname)
|
|
152
165
|
// console.log({ evaluating: { qname, qrl, qcount, jobsLeft, activeQrlsHasQrl: activeQrls.has(qrl) } })
|
|
153
166
|
if (jobsLeft <= 0) break
|
|
154
|
-
if (
|
|
167
|
+
if (listeningQrls.has(qrl)) continue
|
|
155
168
|
const maxMessages = Math.min(10, jobsLeft)
|
|
156
169
|
listen(qname, qrl, maxMessages)
|
|
157
170
|
jobsLeft -= maxMessages
|
|
158
171
|
// debug({ listenedTo: { qname, maxMessages, jobsLeft } })
|
|
159
172
|
}
|
|
160
|
-
await delay(
|
|
173
|
+
await delay(300)
|
|
161
174
|
}
|
|
162
175
|
debug('after all')
|
|
163
176
|
}
|
package/src/idleQueues.js
CHANGED
|
@@ -7,7 +7,7 @@ import { getCloudWatchClient } from './cloudWatch.js'
|
|
|
7
7
|
import { getOptionsWithDefaults } from './defaults.js'
|
|
8
8
|
import { GetQueueAttributesCommand, DeleteQueueCommand, QueueDoesNotExist } from '@aws-sdk/client-sqs'
|
|
9
9
|
import { GetMetricStatisticsCommand } from '@aws-sdk/client-cloudwatch'
|
|
10
|
-
import { normalizeFailQueueName, normalizeDLQName, getQnameUrlPairs, fifoSuffix } from './qrlCache.js'
|
|
10
|
+
import { normalizeFailQueueName, normalizeDLQName, getQnameUrlPairs, fifoSuffix, qrlCacheSet } from './qrlCache.js'
|
|
11
11
|
import { getCache, setCache } from './cache.js'
|
|
12
12
|
// const AWS = require('aws-sdk')
|
|
13
13
|
|
|
@@ -133,7 +133,7 @@ export async function checkIdle (qname, qrl, opt) {
|
|
|
133
133
|
if (cheapResult.idle === false || cheapResult.exists === false) {
|
|
134
134
|
return {
|
|
135
135
|
queue: qname.slice(opt.prefix.length),
|
|
136
|
-
cheap: cheapResult,
|
|
136
|
+
cheap: { SQS, result: cheapResult },
|
|
137
137
|
idle: cheapResult.idle,
|
|
138
138
|
exists: cheapResult.exists,
|
|
139
139
|
apiCalls: { SQS, CloudWatch: 0 }
|
|
@@ -373,6 +373,7 @@ export class JobExecutor {
|
|
|
373
373
|
// Begin tracking jobs
|
|
374
374
|
const jobs = messages.map(message => this.addJob(message, callback, qname, qrl))
|
|
375
375
|
const isFifo = qrl.endsWith('.fifo')
|
|
376
|
+
const runningJobs = []
|
|
376
377
|
|
|
377
378
|
// console.log(jobs)
|
|
378
379
|
|
|
@@ -385,7 +386,8 @@ export class JobExecutor {
|
|
|
385
386
|
// console.log({ i, nextJobAtt: nextJob?.message?.Attributes, nextJobIsSerial })
|
|
386
387
|
// Execute serial or parallel
|
|
387
388
|
if (nextJobIsSerial) await this.runJob(job)
|
|
388
|
-
else this.runJob(job)
|
|
389
|
+
else runningJobs.push(this.runJob(job))
|
|
389
390
|
}
|
|
391
|
+
await Promise.all(runningJobs)
|
|
390
392
|
}
|
|
391
393
|
}
|
|
@@ -71,7 +71,7 @@ export class SystemMonitor {
|
|
|
71
71
|
*/
|
|
72
72
|
|
|
73
73
|
measureLoad () {
|
|
74
|
-
const [newLoad
|
|
74
|
+
const [newLoad] = os.loadavg()
|
|
75
75
|
const previousLoad = this.oneMinuteLoad
|
|
76
76
|
if (previousLoad !== newLoad) {
|
|
77
77
|
const e = 1884 / 2048 // see include/linux/sched/loadavg.h
|
|
@@ -84,7 +84,7 @@ export class SystemMonitor {
|
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
getLoad() {
|
|
87
|
+
getLoad () {
|
|
88
88
|
return this.instantaneousLoad
|
|
89
89
|
}
|
|
90
90
|
|