qdone 1.7.0 → 2.0.0-alpha
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -1
- package/commonjs/index.js +10 -0
- package/commonjs/package.json +3 -0
- package/commonjs/src/cache.js +142 -0
- package/commonjs/src/cloudWatch.js +148 -0
- package/commonjs/src/consumer.js +483 -0
- package/commonjs/src/defaults.js +107 -0
- package/commonjs/src/enqueue.js +498 -0
- package/commonjs/src/idleQueues.js +466 -0
- package/commonjs/src/qrlCache.js +250 -0
- package/commonjs/src/sqs.js +160 -0
- package/npm-shrinkwrap.json +17240 -3367
- package/package.json +41 -29
- package/src/bin.js +3 -0
- package/src/cache.js +18 -22
- package/src/cli.js +268 -182
- package/src/cloudWatch.js +97 -0
- package/src/consumer.js +346 -0
- package/src/defaults.js +114 -0
- package/src/enqueue.js +239 -196
- package/src/idleQueues.js +242 -223
- package/src/monitor.js +53 -0
- package/src/qrlCache.js +110 -83
- package/src/sentry.js +30 -0
- package/src/sqs.js +73 -0
- package/src/worker.js +197 -202
- package/.coveralls.yml +0 -1
- package/.travis.yml +0 -19
- package/CHANGELOG.md +0 -121
- package/index.js +0 -6
- package/qdone +0 -2
- package/test/fixtures/test-child-kill-linux.sh +0 -9
- package/test/fixtures/test-fifo01-x24.batch +0 -24
- package/test/fixtures/test-too-big-1.batch +0 -10
- package/test/fixtures/test-unique01-x24.batch +0 -24
- package/test/fixtures/test-unique02-x24.batch +0 -24
- package/test/fixtures/test-unique24-x24.batch +0 -24
- package/test/fixtures/test-unique24-x240.batch +0 -240
- package/test/test.cache.js +0 -61
- package/test/test.cli.js +0 -1609
package/src/enqueue.js
CHANGED
|
@@ -1,65 +1,153 @@
|
|
|
1
|
+
// const Q = require('q')
|
|
2
|
+
// const debug = require('debug')('qdone:enqueue')
|
|
3
|
+
// const chalk = require('chalk')
|
|
4
|
+
// const uuid = require('uuid')
|
|
5
|
+
// const qrlCache = require('./qrlCache')
|
|
6
|
+
// const AWS = require('aws-sdk')
|
|
1
7
|
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
+
import { v1 as uuidV1 } from 'uuid'
|
|
9
|
+
import chalk from 'chalk'
|
|
10
|
+
import Debug from 'debug'
|
|
11
|
+
import {
|
|
12
|
+
CreateQueueCommand,
|
|
13
|
+
GetQueueAttributesCommand,
|
|
14
|
+
SendMessageCommand,
|
|
15
|
+
SendMessageBatchCommand,
|
|
16
|
+
QueueDoesNotExist
|
|
17
|
+
} from '@aws-sdk/client-sqs'
|
|
8
18
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
19
|
+
import {
|
|
20
|
+
qrlCacheGet,
|
|
21
|
+
qrlCacheSet,
|
|
22
|
+
normalizeQueueName,
|
|
23
|
+
normalizeFailQueueName,
|
|
24
|
+
normalizeDLQName
|
|
25
|
+
} from './qrlCache.js'
|
|
26
|
+
import { getSQSClient } from './sqs.js'
|
|
27
|
+
import { getOptionsWithDefaults } from './defaults.js'
|
|
28
|
+
|
|
29
|
+
const debug = Debug('qdone:enqueue')
|
|
30
|
+
|
|
31
|
+
export async function getOrCreateDLQ (queue, opt) {
|
|
32
|
+
debug('getOrCreateDLQ(', queue, ')')
|
|
33
|
+
const dqname = normalizeDLQName(queue, opt)
|
|
34
|
+
try {
|
|
35
|
+
const dqrl = await qrlCacheGet(dqname)
|
|
36
|
+
return dqrl
|
|
37
|
+
} catch (err) {
|
|
38
|
+
// Anything other than queue doesn't exist gets re-thrown
|
|
39
|
+
if (!(err instanceof QueueDoesNotExist)) throw err
|
|
40
|
+
|
|
41
|
+
// Create our DLQ
|
|
42
|
+
const client = getSQSClient()
|
|
43
|
+
const params = {
|
|
44
|
+
Attributes: { MessageRetentionPeriod: opt.messageRetentionPeriod + '' },
|
|
45
|
+
QueueName: dqname
|
|
46
|
+
}
|
|
47
|
+
if (opt.tags) params.tags = opt.tags
|
|
48
|
+
if (opt.fifo) params.Attributes.FifoQueue = 'true'
|
|
49
|
+
const cmd = new CreateQueueCommand(params)
|
|
50
|
+
if (opt.verbose) console.error(chalk.blue('Creating dead letter queue ') + dqname)
|
|
51
|
+
const data = await client.send(cmd)
|
|
52
|
+
debug('createQueue returned', data)
|
|
53
|
+
const dqrl = data.QueueUrl
|
|
54
|
+
qrlCacheSet(dqname, dqrl)
|
|
55
|
+
return dqrl
|
|
16
56
|
}
|
|
17
|
-
if (options.fifo) params.Attributes.FifoQueue = 'true'
|
|
18
|
-
return sqs
|
|
19
|
-
.createQueue(params)
|
|
20
|
-
.promise()
|
|
21
|
-
.then(function (data) {
|
|
22
|
-
debug('createQueue returned', data)
|
|
23
|
-
return data.QueueUrl
|
|
24
|
-
})
|
|
25
57
|
}
|
|
26
58
|
|
|
27
|
-
function
|
|
28
|
-
debug('
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
59
|
+
export async function getOrCreateFailQueue (queue, opt) {
|
|
60
|
+
debug('getOrCreateFailQueue(', queue, ')')
|
|
61
|
+
const fqname = normalizeFailQueueName(queue, opt)
|
|
62
|
+
try {
|
|
63
|
+
const fqrl = await qrlCacheGet(fqname)
|
|
64
|
+
return fqrl
|
|
65
|
+
} catch (err) {
|
|
66
|
+
// Anything other than queue doesn't exist gets re-thrown
|
|
67
|
+
if (!(err instanceof QueueDoesNotExist)) throw err
|
|
68
|
+
|
|
69
|
+
// Crate our fail queue
|
|
70
|
+
const client = getSQSClient()
|
|
71
|
+
const params = {
|
|
72
|
+
Attributes: { MessageRetentionPeriod: opt.messageRetentionPeriod + '' },
|
|
73
|
+
QueueName: fqname
|
|
74
|
+
}
|
|
75
|
+
// If we have a dlq, we grab it and set a redrive policy
|
|
76
|
+
if (opt.dlq) {
|
|
77
|
+
const dqrl = await getOrCreateDLQ(queue, opt)
|
|
78
|
+
const dqa = await getQueueAttributes(dqrl)
|
|
79
|
+
debug('dqa', dqa)
|
|
80
|
+
params.Attributes.RedrivePolicy = JSON.stringify({
|
|
81
|
+
deadLetterTargetArn: dqa.Attributes.QueueArn,
|
|
82
|
+
maxReceiveCount: opt.dlqAfter + ''
|
|
83
|
+
})
|
|
84
|
+
}
|
|
85
|
+
if (opt.tags) params.tags = opt.tags
|
|
86
|
+
if (opt.fifo) params.Attributes.FifoQueue = 'true'
|
|
87
|
+
const cmd = new CreateQueueCommand(params)
|
|
88
|
+
if (opt.verbose) console.error(chalk.blue('Creating fail queue ') + fqname)
|
|
89
|
+
const data = await client.send(cmd)
|
|
90
|
+
debug('createQueue returned', data)
|
|
91
|
+
const fqrl = data.QueueUrl
|
|
92
|
+
qrlCacheSet(fqname, fqrl)
|
|
93
|
+
return fqrl
|
|
36
94
|
}
|
|
37
|
-
if (options.fifo) params.Attributes.FifoQueue = 'true'
|
|
38
|
-
return sqs
|
|
39
|
-
.createQueue(params)
|
|
40
|
-
.promise()
|
|
41
|
-
.then(function (data) {
|
|
42
|
-
debug('createQueue returned', data)
|
|
43
|
-
return data.QueueUrl
|
|
44
|
-
})
|
|
45
95
|
}
|
|
46
96
|
|
|
47
|
-
|
|
97
|
+
/**
|
|
98
|
+
* Returns a qrl for a queue that either exists or does not
|
|
99
|
+
*/
|
|
100
|
+
export async function getOrCreateQueue (queue, opt) {
|
|
101
|
+
debug('getOrCreateQueue(', queue, ')')
|
|
102
|
+
const qname = normalizeQueueName(queue, opt)
|
|
103
|
+
try {
|
|
104
|
+
const qrl = await qrlCacheGet(qname)
|
|
105
|
+
return qrl
|
|
106
|
+
} catch (err) {
|
|
107
|
+
// Anything other than queue doesn't exist gets re-thrown
|
|
108
|
+
if (!(err instanceof QueueDoesNotExist)) throw err
|
|
109
|
+
|
|
110
|
+
// Get our fail queue so we can create our own
|
|
111
|
+
const fqrl = await getOrCreateFailQueue(qname, opt)
|
|
112
|
+
const fqa = await getQueueAttributes(fqrl)
|
|
113
|
+
|
|
114
|
+
// Create our queue
|
|
115
|
+
const client = getSQSClient()
|
|
116
|
+
const params = {
|
|
117
|
+
Attributes: {
|
|
118
|
+
MessageRetentionPeriod: opt.messageRetentionPeriod + '',
|
|
119
|
+
RedrivePolicy: JSON.stringify({
|
|
120
|
+
deadLetterTargetArn: fqa.Attributes.QueueArn,
|
|
121
|
+
maxReceiveCount: '1'
|
|
122
|
+
})
|
|
123
|
+
},
|
|
124
|
+
QueueName: qname
|
|
125
|
+
}
|
|
126
|
+
if (opt.tags) params.tags = opt.tags
|
|
127
|
+
if (opt.fifo) params.Attributes.FifoQueue = 'true'
|
|
128
|
+
const cmd = new CreateQueueCommand(params)
|
|
129
|
+
debug({ params })
|
|
130
|
+
if (opt.verbose) console.error(chalk.blue('Creating queue ') + qname)
|
|
131
|
+
const data = await client.send(cmd)
|
|
132
|
+
debug('createQueue returned', data)
|
|
133
|
+
const qrl = data.QueueUrl
|
|
134
|
+
qrlCacheSet(qname, qrl)
|
|
135
|
+
return qrl
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export async function getQueueAttributes (qrl) {
|
|
48
140
|
debug('getQueueAttributes(', qrl, ')')
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
.then(function (data) {
|
|
57
|
-
debug('getQueueAttributes returned', data)
|
|
58
|
-
return data
|
|
59
|
-
})
|
|
141
|
+
const client = getSQSClient()
|
|
142
|
+
const params = { AttributeNames: ['All'], QueueUrl: qrl }
|
|
143
|
+
const cmd = new GetQueueAttributesCommand(params)
|
|
144
|
+
// debug({ cmd })
|
|
145
|
+
const data = await client.send(cmd)
|
|
146
|
+
debug('GetQueueAttributes returned', data)
|
|
147
|
+
return data
|
|
60
148
|
}
|
|
61
149
|
|
|
62
|
-
function formatMessage (command, id) {
|
|
150
|
+
export function formatMessage (command, id) {
|
|
63
151
|
const message = {
|
|
64
152
|
/*
|
|
65
153
|
MessageAttributes: {
|
|
@@ -73,88 +161,93 @@ function formatMessage (command, id) {
|
|
|
73
161
|
return message
|
|
74
162
|
}
|
|
75
163
|
|
|
76
|
-
function sendMessage (qrl, command,
|
|
164
|
+
export async function sendMessage (qrl, command, opt) {
|
|
77
165
|
debug('sendMessage(', qrl, command, ')')
|
|
78
|
-
const
|
|
166
|
+
const params = Object.assign({ QueueUrl: qrl }, formatMessage(command))
|
|
79
167
|
// Add in group id if we're using fifo
|
|
80
|
-
if (
|
|
81
|
-
|
|
82
|
-
|
|
168
|
+
if (opt.fifo) {
|
|
169
|
+
params.MessageGroupId = opt.groupId
|
|
170
|
+
params.MessageDeduplicationId = opt.deduplicationId
|
|
83
171
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
})
|
|
172
|
+
if (opt.delay) params.DelaySeconds = opt.delay
|
|
173
|
+
const client = getSQSClient()
|
|
174
|
+
const cmd = new SendMessageCommand(params)
|
|
175
|
+
debug({ cmd })
|
|
176
|
+
const data = await client.send(cmd)
|
|
177
|
+
debug('sendMessage returned', data)
|
|
178
|
+
return data
|
|
92
179
|
}
|
|
93
180
|
|
|
94
|
-
function sendMessageBatch (qrl, messages,
|
|
181
|
+
export async function sendMessageBatch (qrl, messages, opt) {
|
|
95
182
|
debug('sendMessageBatch(', qrl, messages.map(e => Object.assign(Object.assign({}, e), { MessageBody: e.MessageBody.slice(0, 10) + '...' })), ')')
|
|
96
183
|
const params = { Entries: messages, QueueUrl: qrl }
|
|
184
|
+
const uuidFunction = opt.uuidFunction || uuidV1
|
|
97
185
|
// Add in group id if we're using fifo
|
|
98
|
-
if (
|
|
186
|
+
if (opt.fifo) {
|
|
99
187
|
params.Entries = params.Entries.map(
|
|
100
188
|
message => Object.assign({
|
|
101
|
-
MessageGroupId:
|
|
102
|
-
MessageDeduplicationId:
|
|
189
|
+
MessageGroupId: opt.groupIdPerMessage ? uuidFunction() : opt.groupId,
|
|
190
|
+
MessageDeduplicationId: uuidFunction()
|
|
103
191
|
}, message)
|
|
104
192
|
)
|
|
105
193
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
194
|
+
if (opt.delay) {
|
|
195
|
+
params.Entries = params.Entries.map(message =>
|
|
196
|
+
Object.assign({ DelaySeconds: opt.delay }, message))
|
|
197
|
+
}
|
|
198
|
+
const client = getSQSClient()
|
|
199
|
+
const cmd = new SendMessageBatchCommand(params)
|
|
200
|
+
debug({ cmd })
|
|
201
|
+
const data = await client.send(cmd)
|
|
202
|
+
debug('sendMessageBatch returned', data)
|
|
203
|
+
return data
|
|
114
204
|
}
|
|
115
205
|
|
|
116
206
|
const messages = {}
|
|
117
|
-
|
|
207
|
+
let requestCount = 0
|
|
118
208
|
|
|
119
209
|
//
|
|
120
210
|
// Flushes the internal message buffer for qrl.
|
|
121
211
|
// If the message is too large, batch is retried with half the messages.
|
|
122
212
|
// Returns number of messages flushed.
|
|
123
213
|
//
|
|
124
|
-
function flushMessages (qrl,
|
|
214
|
+
export async function flushMessages (qrl, opt) {
|
|
125
215
|
debug('flushMessages', qrl)
|
|
126
216
|
// Flush until empty
|
|
127
|
-
|
|
128
|
-
function whileNotEmpty () {
|
|
217
|
+
let numFlushed = 0
|
|
218
|
+
async function whileNotEmpty () {
|
|
129
219
|
if (!(messages[qrl] && messages[qrl].length)) return numFlushed
|
|
130
220
|
// Construct batch until full
|
|
131
221
|
const batch = []
|
|
132
|
-
|
|
133
|
-
|
|
222
|
+
let nextSize = JSON.stringify(messages[qrl][0]).length
|
|
223
|
+
let totalSize = 0
|
|
134
224
|
while ((totalSize + nextSize) < 262144 && messages[qrl].length && batch.length < 10) {
|
|
135
225
|
batch.push(messages[qrl].shift())
|
|
136
226
|
totalSize += nextSize
|
|
137
227
|
if (messages[qrl].length) nextSize = JSON.stringify(messages[qrl][0]).length
|
|
138
228
|
else nextSize = 0
|
|
139
229
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
230
|
+
|
|
231
|
+
// Send batch
|
|
232
|
+
const data = await sendMessageBatch(qrl, batch, opt)
|
|
233
|
+
debug({ data })
|
|
234
|
+
|
|
235
|
+
// Fail if there are any individual message failures
|
|
236
|
+
if (data.Failed && data.Failed.length) {
|
|
237
|
+
const err = new Error('One or more message failures: ' + JSON.stringify(data.Failed))
|
|
238
|
+
err.Failed = data.Failed
|
|
239
|
+
throw err
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// If we actually managed to flush any of them
|
|
243
|
+
if (batch.length) {
|
|
244
|
+
requestCount += 1
|
|
245
|
+
data.Successful.forEach(message => {
|
|
246
|
+
if (opt.verbose) console.error(chalk.blue('Enqueued job ') + message.MessageId + chalk.blue(' request ' + requestCount))
|
|
156
247
|
})
|
|
157
|
-
.
|
|
248
|
+
numFlushed += batch.length
|
|
249
|
+
}
|
|
250
|
+
return whileNotEmpty()
|
|
158
251
|
}
|
|
159
252
|
return whileNotEmpty()
|
|
160
253
|
}
|
|
@@ -164,125 +257,75 @@ function flushMessages (qrl, options) {
|
|
|
164
257
|
// Automaticaly flushes if queue has >= 10 messages.
|
|
165
258
|
// Returns number of messages flushed.
|
|
166
259
|
//
|
|
167
|
-
|
|
168
|
-
function addMessage (qrl, command,
|
|
260
|
+
let messageIndex = 0
|
|
261
|
+
export async function addMessage (qrl, command, opt) {
|
|
169
262
|
const message = formatMessage(command, messageIndex++)
|
|
170
263
|
messages[qrl] = messages[qrl] || []
|
|
171
264
|
messages[qrl].push(message)
|
|
172
|
-
if (messages[qrl].length
|
|
173
|
-
return flushMessages(qrl,
|
|
265
|
+
if (messages[qrl].length >= 10) {
|
|
266
|
+
return flushMessages(qrl, opt)
|
|
174
267
|
}
|
|
175
268
|
return 0
|
|
176
269
|
}
|
|
177
270
|
|
|
178
|
-
//
|
|
179
|
-
// Fetches (or returns cached) the qrl
|
|
180
|
-
//
|
|
181
|
-
function getQrl (queue, qname, fqueue, fqname, options) {
|
|
182
|
-
debug('getQrl', queue, qname, fqueue, fqname)
|
|
183
|
-
// Normal queue
|
|
184
|
-
const qrl = qrlCache
|
|
185
|
-
.get(qname)
|
|
186
|
-
.catch(function (err) {
|
|
187
|
-
// Create our queue if it doesn't exist
|
|
188
|
-
if (err.code === 'AWS.SimpleQueueService.NonExistentQueue') {
|
|
189
|
-
// Grab fail queue
|
|
190
|
-
const fqrl = qrlCache
|
|
191
|
-
.get(fqname)
|
|
192
|
-
.catch(function (err) {
|
|
193
|
-
// Create fail queue if it doesn't exist
|
|
194
|
-
if (err.code === 'AWS.SimpleQueueService.NonExistentQueue') {
|
|
195
|
-
if (options.verbose) console.error(chalk.blue('Creating fail queue ') + fqueue)
|
|
196
|
-
return createFailQueue(fqueue, fqname, null, options)
|
|
197
|
-
}
|
|
198
|
-
throw err // throw unhandled errors
|
|
199
|
-
})
|
|
200
|
-
|
|
201
|
-
// Need to grab fail queue's ARN to create our queue
|
|
202
|
-
return fqrl
|
|
203
|
-
.then(getQueueAttributes)
|
|
204
|
-
.then(data => {
|
|
205
|
-
if (options.verbose) console.error(chalk.blue('Creating queue ') + queue)
|
|
206
|
-
return createQueue(queue, qname, data.Attributes.QueueArn, options)
|
|
207
|
-
})
|
|
208
|
-
}
|
|
209
|
-
throw err // throw unhandled errors
|
|
210
|
-
})
|
|
211
|
-
|
|
212
|
-
return qrl
|
|
213
|
-
}
|
|
214
|
-
|
|
215
271
|
//
|
|
216
272
|
// Enqueue a single command
|
|
217
273
|
// Returns a promise for the SQS API response.
|
|
218
274
|
//
|
|
219
|
-
|
|
220
|
-
debug('enqueue(', queue, command, ')')
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
const fqueue = qrlCache.normalizeFailQueueName(queue, options)
|
|
225
|
-
const fqname = options.prefix + fqueue
|
|
226
|
-
|
|
227
|
-
// Now that we have the queue, send our message
|
|
228
|
-
return getQrl(queue, qname, fqueue, fqname, options)
|
|
229
|
-
.then(qrl => sendMessage(qrl, command, options))
|
|
275
|
+
export async function enqueue (queue, command, options) {
|
|
276
|
+
debug('enqueue(', { queue, command }, ')')
|
|
277
|
+
const opt = getOptionsWithDefaults(options)
|
|
278
|
+
const qrl = await getOrCreateQueue(queue, opt)
|
|
279
|
+
return sendMessage(qrl, command, opt)
|
|
230
280
|
}
|
|
231
281
|
|
|
232
282
|
//
|
|
233
283
|
// Enqueue many commands formatted as an array of {queue: ..., command: ...} pairs.
|
|
234
284
|
// Returns a promise for the total number of messages enqueued.
|
|
235
285
|
//
|
|
236
|
-
|
|
286
|
+
export async function enqueueBatch (pairs, options) {
|
|
237
287
|
debug('enqueueBatch(', pairs, ')')
|
|
288
|
+
const opt = getOptionsWithDefaults(options)
|
|
238
289
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
}
|
|
290
|
+
// Find unique queues so we can pre-fetch qrls. We do this so that all
|
|
291
|
+
// queues are created prior to going through our flush logic
|
|
292
|
+
const normalizedPairs = pairs.map(({ queue, command }) => ({
|
|
293
|
+
qname: normalizeQueueName(queue, opt),
|
|
294
|
+
command
|
|
295
|
+
}))
|
|
296
|
+
const uniqueQnames = new Set(normalizedPairs.map(p => p.qname))
|
|
247
297
|
|
|
248
|
-
//
|
|
249
|
-
const
|
|
250
|
-
const
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
uniquePairs.push(pair)
|
|
255
|
-
}
|
|
256
|
-
})
|
|
257
|
-
debug({ uniquePairMap, uniquePairs })
|
|
298
|
+
// Prefetch qrls / create queues in parallel
|
|
299
|
+
const createPromises = []
|
|
300
|
+
for (const qname of uniqueQnames) {
|
|
301
|
+
createPromises.push(getOrCreateQueue(qname, opt))
|
|
302
|
+
}
|
|
303
|
+
await Promise.all(createPromises)
|
|
258
304
|
|
|
259
|
-
//
|
|
305
|
+
// After we've prefetched, all qrls are in cache
|
|
306
|
+
// so go back through the list of pairs and fire off messages
|
|
260
307
|
requestCount = 0
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
.all(Object.keys(messages).map(key => flushMessages(key, options))) // messages is the global flush buffer
|
|
283
|
-
.then(flushCounts => flushCounts.reduce((a, b) => a + b, totalFlushed))
|
|
284
|
-
})
|
|
285
|
-
})
|
|
308
|
+
const addMessagePromises = []
|
|
309
|
+
for (const { qname, command } of normalizedPairs) {
|
|
310
|
+
const qrl = await getOrCreateQueue(qname, opt)
|
|
311
|
+
addMessagePromises.push(addMessage(qrl, command, opt))
|
|
312
|
+
}
|
|
313
|
+
const flushCounts = await Promise.all(addMessagePromises)
|
|
314
|
+
|
|
315
|
+
// Count up how many were flushed during add
|
|
316
|
+
debug('flushCounts', flushCounts)
|
|
317
|
+
const initialFlushTotal = flushCounts.reduce((a, b) => a + b, 0)
|
|
318
|
+
|
|
319
|
+
// And flush any remaining messages
|
|
320
|
+
const extraFlushPromises = []
|
|
321
|
+
for (const qrl in messages) {
|
|
322
|
+
extraFlushPromises.push(flushMessages(qrl, opt))
|
|
323
|
+
}
|
|
324
|
+
const extraFlushCounts = await Promise.all(extraFlushPromises)
|
|
325
|
+
const extraFlushTotal = extraFlushCounts.reduce((a, b) => a + b, 0)
|
|
326
|
+
const totalFlushed = initialFlushTotal + extraFlushTotal
|
|
327
|
+
debug({ initialFlushTotal, extraFlushTotal, totalFlushed })
|
|
328
|
+
return totalFlushed
|
|
286
329
|
}
|
|
287
330
|
|
|
288
331
|
debug('loaded')
|