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.
Files changed (3) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/index.js +71 -82
  3. 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, cb) {
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
- acapi.aclog.hrLine()
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
- acapi.aclog.listing({ field: 'Listener', value: 'Activated' })
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
- acapi.aclog.listing({ field: 'Worker', value: 'Activated' })
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
- return cb()
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, cb) {
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) return cb({ message: 'jobListNotDefined', additionalInfo: { jobList } })
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]) return cb({ message: 'bullNotAvailableForQueueName', additionalInfo: { 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
- async.series({
191
- addJob: (done) => {
192
- if (name) {
193
- acapi.bull[queueName].add(name, jobPayload, jobOptions).then(job => {
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
- }, (err) => {
214
- if (_.get(params, 'debug')) acapi.log.info('%s | %s | %s | %s | Adding job to queue', functionName, functionIdentifier, queueName, jobId)
215
- return cb(err, { jobId })
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
- async.series({
229
- removeKeyFromWatchList: (done) => {
230
- if (!jobListWatchKey || !_.isObject(acapi.redis[_.get(acapi.config, 'bull.redis.database.name')])) return done()
231
- acapi.redis[_.get(acapi.config, 'bull.redis.database.name')].hdel(jobListWatchKey, jobId, done)
232
- },
233
- removeJob: (done) => {
234
- job.remove()
235
- return done()
236
- },
237
- cleanUpActivity: async() => {
238
- if (!acapi.redis.mcCache) return
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
- }, function allDone(err) {
247
- if (err) acapi.log.error('%s | %s | %s | %s | Failed %j', functionName, functionIdentifier, queueName, jobId, err)
248
- else acapi.log.info('%s | %s | %s | # %s | Successful', functionName, functionIdentifier, queueName, jobId)
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, cb) {
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) return cb({ message: 'queueNameMissing', additionalInfo: params })
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
- redisLock.lockKey({ redisKey }, err => {
264
- if (err === 423) {
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
- if (_.isFunction(cb)) return cb(423)
264
+ throw e
267
265
  }
268
- else if (err) {
269
- acapi.log.error('%s | %s | %s | # %s | Failed %j', functionName, functionIdentifier, queueName, jobId, err)
270
- if (_.isFunction(cb)) return cb(err)
266
+ else {
267
+ acapi.log.error('%s | %s | %s | # %s | Failed %j', functionName, functionIdentifier, queueName, jobId, e?.message)
268
+ throw e
271
269
  }
272
- acapi.bull[queueName].getJob(jobId).then((result) => {
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(cb) {
290
- async.each(this.jobLists, (queueName, itDone) => {
291
- acapi.bull[queueName].close().then(itDone)
292
- }, cb)
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": "2.1.2",
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": "^3.0.0",
10
- "async": "^3.2.6",
11
- "bull": "^4.16.4",
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.3",
17
- "eslint": "^9.16.0"
18
- }
15
+ "ac-semantic-release": "^0.4.6",
16
+ "eslint": "^9.26.0"
17
+ },
18
+ "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
19
19
  }