ac-bootstrap-bull 2.1.2 → 3.0.0
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/CHANGELOG.md +20 -0
- package/index.js +71 -82
- package/package.json +8 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,23 @@
|
|
|
1
|
+
|
|
2
|
+
# [3.0.0](https://github.com/admiralcloud/ac-bootstrap-bull/compare/v2.1.3..v3.0.0) (2025-05-06 18:07:40)
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
### Bug Fix
|
|
6
|
+
|
|
7
|
+
* **App:** Use redisLock@4 | MP | [8661bdea86562e9b0a1ecb1beebc3a9668fc1a11](https://github.com/admiralcloud/ac-bootstrap-bull/commit/8661bdea86562e9b0a1ecb1beebc3a9668fc1a11)
|
|
8
|
+
Use redisLock@4 and return logs instead of logging to stdout.
|
|
9
|
+
Related issues:
|
|
10
|
+
## BREAKING CHANGES
|
|
11
|
+
* **App:** Version works with async/await and RedisLock 4
|
|
12
|
+
|
|
13
|
+
## [2.1.3](https://github.com/admiralcloud/ac-bootstrap-bull/compare/v2.1.2..v2.1.3) (2025-03-01 07:20:58)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### Bug Fix
|
|
17
|
+
|
|
18
|
+
* **App:** Package updates | MP | [82c47bd9fad446d94613a40bbda40749714a6a56](https://github.com/admiralcloud/ac-bootstrap-bull/commit/82c47bd9fad446d94613a40bbda40749714a6a56)
|
|
19
|
+
Package updates
|
|
20
|
+
Related issues:
|
|
1
21
|
<a name="2.1.2"></a>
|
|
2
22
|
|
|
3
23
|
## [2.1.2](https://github.com/admiralcloud/ac-bootstrap-bull/compare/v2.1.1..v2.1.2) (2024-12-01 17:02:13)
|
package/index.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
const Queue = require('bull')
|
|
2
2
|
const _ = require('lodash')
|
|
3
3
|
const Redis = require('ioredis')
|
|
4
|
-
const async = require('async')
|
|
5
4
|
const redisLock = require('ac-redislock')
|
|
6
5
|
const { v4: uuidV4 } = require('uuid')
|
|
7
6
|
|
|
@@ -13,6 +12,7 @@ module.exports = function(acapi) {
|
|
|
13
12
|
_.set(acapi.config, 'bull.redis.database.name', _.get(params, 'redis.config', 'jobProcessing'))
|
|
14
13
|
}
|
|
15
14
|
|
|
15
|
+
let logCollector = []
|
|
16
16
|
const jobLists = []
|
|
17
17
|
|
|
18
18
|
/**
|
|
@@ -31,8 +31,7 @@ module.exports = function(acapi) {
|
|
|
31
31
|
return { queueName, jobListConfig }
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
const init = function(params
|
|
35
|
-
acapi.aclog.headline({ headline: 'bull' })
|
|
34
|
+
const init = async function(params) {
|
|
36
35
|
|
|
37
36
|
// prepare some vars for this scope of this module
|
|
38
37
|
this.scope(params)
|
|
@@ -51,7 +50,8 @@ module.exports = function(acapi) {
|
|
|
51
50
|
},
|
|
52
51
|
enableReadyCheck: false,
|
|
53
52
|
maxRetriesPerRequest: null,
|
|
54
|
-
enableAutoPipelining: _.get(acapi.config, 'bull.enableAutoPipelining', false)
|
|
53
|
+
enableAutoPipelining: _.get(acapi.config, 'bull.enableAutoPipelining', false),
|
|
54
|
+
collectOnly: true
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
if (acapi.config.localRedis) {
|
|
@@ -60,7 +60,8 @@ module.exports = function(acapi) {
|
|
|
60
60
|
})
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
acapi.aclog.serverInfo(redisConf)
|
|
63
|
+
logCollector = _.concat(logCollector, acapi.aclog.serverInfo(redisConf))
|
|
64
|
+
logCollector.push({ line: true })
|
|
64
65
|
|
|
65
66
|
const errorHistory = {}
|
|
66
67
|
|
|
@@ -96,23 +97,18 @@ module.exports = function(acapi) {
|
|
|
96
97
|
}
|
|
97
98
|
|
|
98
99
|
// Redislock cannot be re-used from parent application, init here again
|
|
99
|
-
redisLock.init({
|
|
100
|
+
await redisLock.init({
|
|
100
101
|
redis: opts.createClient(),
|
|
101
102
|
logger: acapi.log,
|
|
102
103
|
logLevel: _.get(params, 'logLevel', 'silly'),
|
|
103
104
|
suppressMismatch: true
|
|
104
|
-
}, err => {
|
|
105
|
-
if (err) {
|
|
106
|
-
acapi.log.error('%s | Init RedisLock | Failed %j', functionName, err)
|
|
107
|
-
}
|
|
108
105
|
})
|
|
109
106
|
|
|
110
107
|
// create a bull instance for every jobList, to allow concurrency
|
|
111
108
|
_.forEach(_.get(params, 'jobLists'), jobList => {
|
|
112
109
|
const { queueName } = this.prepareQueue(jobList)
|
|
113
110
|
|
|
114
|
-
|
|
115
|
-
acapi.aclog.listing({ field: 'Queue', value: queueName })
|
|
111
|
+
logCollector.push({ field: 'Queue', value: queueName })
|
|
116
112
|
this.jobLists.push(queueName)
|
|
117
113
|
|
|
118
114
|
acapi.bull[queueName] = new Queue(queueName, opts)
|
|
@@ -121,20 +117,21 @@ module.exports = function(acapi) {
|
|
|
121
117
|
// this job's listener is on this API
|
|
122
118
|
acapi.bull[queueName].on('global:completed', _.get(params, 'handlers.global:completed')[_.get(jobList, 'jobList')])
|
|
123
119
|
acapi.bull[queueName].on('global:failed', _.get(params, 'handlers.global:failed', this.handleFailedJobs).bind(this, queueName))
|
|
124
|
-
|
|
120
|
+
logCollector.push({ field: 'Listener', value: 'Activated' })
|
|
125
121
|
}
|
|
126
122
|
if (_.get(jobList, 'worker')) {
|
|
127
123
|
// this job's worker is on this API (BatchProcessCollector[jobList])
|
|
128
124
|
let workerFN = _.get(params, 'worker')[_.get(jobList, 'jobList')]
|
|
129
125
|
workerFN(jobList)
|
|
130
|
-
|
|
126
|
+
logCollector.push({ field: 'Worker', value: 'Activated' })
|
|
131
127
|
}
|
|
132
128
|
if (_.get(jobList, 'autoClean')) {
|
|
133
129
|
acapi.bull[queueName].clean(_.get(jobList, 'autoClean', _.get(acapi.config, 'bull.autoClean')))
|
|
134
130
|
}
|
|
135
131
|
}
|
|
136
132
|
})
|
|
137
|
-
|
|
133
|
+
|
|
134
|
+
return logCollector
|
|
138
135
|
}
|
|
139
136
|
|
|
140
137
|
const handleFailedJobs = (jobList, jobId, err) => {
|
|
@@ -151,10 +148,10 @@ module.exports = function(acapi) {
|
|
|
151
148
|
*
|
|
152
149
|
*/
|
|
153
150
|
|
|
154
|
-
const addJob = function(jobList, params
|
|
151
|
+
const addJob = async function(jobList, params) {
|
|
155
152
|
const functionIdentifier = _.padEnd('addJob', _.get(acapi.config, 'bull.log.functionIdentifierLength'))
|
|
156
153
|
const { queueName } = this.prepareQueue({ jobList, configPath: _.get(params, 'configPath'), customJobList: _.get(params, 'customJobList'), ignore: _.get(params, 'ignore') })
|
|
157
|
-
if (!queueName)
|
|
154
|
+
if (!queueName) throw new ACError('jobListNotDefined', -1, { jobList })
|
|
158
155
|
|
|
159
156
|
const name = _.get(params, 'name') // named job
|
|
160
157
|
const jobPayload = _.get(params, 'jobPayload')
|
|
@@ -183,40 +180,33 @@ module.exports = function(acapi) {
|
|
|
183
180
|
_.set(jobPayload, 'jobListWatchKey', jobListWatchKey)
|
|
184
181
|
}
|
|
185
182
|
|
|
186
|
-
if (!acapi.bull[queueName])
|
|
183
|
+
if (!acapi.bull[queueName]) throw new ACError('bullNotAvailableForQueueName', -1, { queueName })
|
|
187
184
|
//acapi.log.error('195 %j %j %j %j %j', queueName, name, jobPayload, jobOptions, addToWatchList)
|
|
188
185
|
|
|
186
|
+
// add job
|
|
189
187
|
let jobId
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
jobId = _.get(job, 'id')
|
|
195
|
-
return done()
|
|
196
|
-
}).catch(err => {
|
|
197
|
-
acapi.log.error('%s | %s | %s | Name %s | Adding job failed %j', functionName, functionIdentifier, queueName, name, err?.message)
|
|
198
|
-
})
|
|
199
|
-
}
|
|
200
|
-
else {
|
|
201
|
-
acapi.bull[queueName].add(jobPayload, jobOptions).then(job => {
|
|
202
|
-
jobId = _.get(job, 'id')
|
|
203
|
-
return done()
|
|
204
|
-
}).catch(err => {
|
|
205
|
-
acapi.log.error('%s | %s | %s | Adding job failed %j', functionName, functionIdentifier, queueName, err?.message)
|
|
206
|
-
})
|
|
207
|
-
}
|
|
208
|
-
},
|
|
209
|
-
addKeyToWatchList: (done) => {
|
|
210
|
-
if (!addToWatchList || !jobListWatchKey || !_.isObject(acapi.redis[_.get(acapi.config, 'bull.redis.database.name')])) return done()
|
|
211
|
-
acapi.redis[_.get(acapi.config, 'bull.redis.database.name')].hset(jobListWatchKey, jobId, queueName, done)
|
|
188
|
+
try {
|
|
189
|
+
if (name) {
|
|
190
|
+
const job = await acapi.bull[queueName].add(name, jobPayload, jobOptions)
|
|
191
|
+
jobId = _.get(job, 'id')
|
|
212
192
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
}
|
|
193
|
+
else {
|
|
194
|
+
const job = acapi.bull[queueName].add(jobPayload, jobOptions)
|
|
195
|
+
jobId = _.get(job, 'id')
|
|
196
|
+
}
|
|
197
|
+
// addKeyToWatchList
|
|
198
|
+
if (addToWatchList && !jobListWatchKey && _.isObject(acapi.redis[_.get(acapi.config, 'bull.redis.database.name')])) {
|
|
199
|
+
await acapi.redis[_.get(acapi.config, 'bull.redis.database.name')].hset(jobListWatchKey, jobId, queueName)
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
catch(e) {
|
|
203
|
+
acapi.log.error('%s | %s | %s | Adding job failed %j', functionName, functionIdentifier, queueName, e?.message)
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return { jobId }
|
|
217
207
|
}
|
|
218
208
|
|
|
219
|
-
const removeJob = (job, queueName) => {
|
|
209
|
+
const removeJob = async(job, queueName) => {
|
|
220
210
|
const functionIdentifier = _.padEnd('removeJob', _.get(acapi.config, 'bull.log.functionIdentifierLength'))
|
|
221
211
|
if (_.isNil(job)) {
|
|
222
212
|
acapi.log.error('%s | %s | %s | Job invalid %j', functionName, functionIdentifier, queueName, job)
|
|
@@ -225,17 +215,17 @@ module.exports = function(acapi) {
|
|
|
225
215
|
const jobId = _.get(job, 'id')
|
|
226
216
|
const jobListWatchKey = _.get(job, 'data.jobListWatchKey')
|
|
227
217
|
|
|
228
|
-
|
|
229
|
-
removeKeyFromWatchList
|
|
230
|
-
|
|
231
|
-
acapi.redis[_.get(acapi.config, 'bull.redis.database.name')].hdel(jobListWatchKey, jobId
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
cleanUpActivity
|
|
238
|
-
|
|
218
|
+
try {
|
|
219
|
+
// removeKeyFromWatchList
|
|
220
|
+
if (jobListWatchKey && _.isObject(acapi.redis[_.get(acapi.config, 'bull.redis.database.name')])) {
|
|
221
|
+
await acapi.redis[_.get(acapi.config, 'bull.redis.database.name')].hdel(jobListWatchKey, jobId)
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// removeJob
|
|
225
|
+
await job.remove()
|
|
226
|
+
|
|
227
|
+
//cleanUpActivity
|
|
228
|
+
if (acapi.redis.mcCache) {
|
|
239
229
|
const [ customerId, jobIdentifier ] = jobId.split(':::')
|
|
240
230
|
const redisKey = `${acapi.config.environment}:v5:${customerId}:activities`
|
|
241
231
|
const multi = acapi.redis.mcCache.multi()
|
|
@@ -243,13 +233,14 @@ module.exports = function(acapi) {
|
|
|
243
233
|
multi.hdel(redisKey, `${jobIdentifier}:progress`)
|
|
244
234
|
await multi.exec()
|
|
245
235
|
}
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
236
|
+
acapi.log.info('%s | %s | %s | # %s | Successful', functionName, functionIdentifier, queueName, jobId)
|
|
237
|
+
}
|
|
238
|
+
catch(e) {
|
|
239
|
+
acapi.log.error('%s | %s | %s | %s | Failed %j', functionName, functionIdentifier, queueName, jobId, e?.message)
|
|
240
|
+
}
|
|
250
241
|
}
|
|
251
242
|
|
|
252
|
-
const postProcessing = function(params
|
|
243
|
+
const postProcessing = async function(params) {
|
|
253
244
|
const functionIdentifier = _.padEnd('postProcessing', _.get(acapi.config, 'bull.log.functionIdentifierLength'))
|
|
254
245
|
const jobList = _.get(params, 'jobList')
|
|
255
246
|
const jobId = _.get(params, 'jobId')
|
|
@@ -257,28 +248,26 @@ module.exports = function(acapi) {
|
|
|
257
248
|
|
|
258
249
|
const redisKey = acapi.config.environment + ':bull:' + jobList + ':' + jobId + ':complete:lock'
|
|
259
250
|
const { queueName, jobListConfig } = this.prepareQueue({ jobList, configPath: _.get(params, 'configPath') })
|
|
260
|
-
if (!queueName)
|
|
251
|
+
if (!queueName) throw new ACError('queueNameMissing', -1, { params })
|
|
261
252
|
const retentionTime = _.get(jobListConfig, 'retentionTime', _.get(acapi.config, 'bull.retentionTime', 60000))
|
|
262
253
|
|
|
263
|
-
|
|
264
|
-
|
|
254
|
+
try {
|
|
255
|
+
await redisLock.lockKey({ redisKey })
|
|
256
|
+
const result = await acapi.bull[queueName].getJob(jobId)
|
|
257
|
+
acapi.log.info('%s | %s | %s | # %s | C/MC %s/%s', functionName, functionIdentifier, queueName, jobId, _.get(result, 'data.customerId', '-'), _.get(result, 'data.mediaContainerId', '-'))
|
|
258
|
+
setTimeout(that.removeJob, retentionTime, result, queueName)
|
|
259
|
+
return result
|
|
260
|
+
}
|
|
261
|
+
catch(e) {
|
|
262
|
+
if (e === 423) {
|
|
265
263
|
acapi.log.debug('%s | %s | %s | # %s | Already processing', functionName, functionIdentifier, queueName, jobId)
|
|
266
|
-
|
|
264
|
+
throw e
|
|
267
265
|
}
|
|
268
|
-
else
|
|
269
|
-
acapi.log.error('%s | %s | %s | # %s | Failed %j', functionName, functionIdentifier, queueName, jobId,
|
|
270
|
-
|
|
266
|
+
else {
|
|
267
|
+
acapi.log.error('%s | %s | %s | # %s | Failed %j', functionName, functionIdentifier, queueName, jobId, e?.message)
|
|
268
|
+
throw e
|
|
271
269
|
}
|
|
272
|
-
|
|
273
|
-
acapi.log.info('%s | %s | %s | # %s | C/MC %s/%s', functionName, functionIdentifier, queueName, jobId, _.get(result, 'data.customerId', '-'), _.get(result, 'data.mediaContainerId', '-'))
|
|
274
|
-
setTimeout(that.removeJob, retentionTime, result, queueName)
|
|
275
|
-
if (_.isFunction(cb)) return cb(null, result)
|
|
276
|
-
acapi.log.info('%s | %s | %s | # %s | Successful', functionName, functionIdentifier, queueName, jobId, _.get(result, 'data.customerId', '-'), _.get(result, 'data.mediaContainerId', '-'))
|
|
277
|
-
}).catch(err => {
|
|
278
|
-
acapi.log.error('%s | %s | %s | # %s | Failed %j', functionName, functionIdentifier, queueName, jobId, err)
|
|
279
|
-
if (_.isFunction(cb)) return cb()
|
|
280
|
-
})
|
|
281
|
-
})
|
|
270
|
+
}
|
|
282
271
|
}
|
|
283
272
|
const prepareProcessing = postProcessing
|
|
284
273
|
|
|
@@ -286,10 +275,10 @@ module.exports = function(acapi) {
|
|
|
286
275
|
/**
|
|
287
276
|
* Shutdown all queues/redis connections
|
|
288
277
|
*/
|
|
289
|
-
const shutdown = function(
|
|
290
|
-
|
|
291
|
-
acapi.bull[queueName].close()
|
|
292
|
-
}
|
|
278
|
+
const shutdown = async function() {
|
|
279
|
+
for (const queueName of this.jobLists) {
|
|
280
|
+
await acapi.bull[queueName].close()
|
|
281
|
+
}
|
|
293
282
|
}
|
|
294
283
|
|
|
295
284
|
return {
|
package/package.json
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ac-bootstrap-bull",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "Bull helper",
|
|
5
5
|
"repository": "admiralcloud/ac-bootstrap-bull",
|
|
6
6
|
"author": "Mark Poepping <mark.poepping@admiralcloud.com>",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"ac-redislock": "^
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"ioredis": "^5.4.1",
|
|
9
|
+
"ac-redislock": "^4.0.0",
|
|
10
|
+
"bull": "^4.16.5",
|
|
11
|
+
"ioredis": "^5.6.1",
|
|
13
12
|
"lodash": "^4.17.21"
|
|
14
13
|
},
|
|
15
14
|
"devDependencies": {
|
|
16
|
-
"ac-semantic-release": "^0.4.
|
|
17
|
-
"eslint": "^9.
|
|
18
|
-
}
|
|
15
|
+
"ac-semantic-release": "^0.4.6",
|
|
16
|
+
"eslint": "^9.26.0"
|
|
17
|
+
},
|
|
18
|
+
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
|
|
19
19
|
}
|