pg-boss 10.3.3 → 11.0.1
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 +3 -3
- package/docker-compose.yaml +1 -1
- package/package.json +3 -3
- package/src/attorney.js +69 -220
- package/src/boss.js +100 -117
- package/src/db.js +3 -0
- package/src/index.js +6 -12
- package/src/manager.js +225 -191
- package/src/migrationStore.js +0 -88
- package/src/plans.js +469 -446
- package/src/timekeeper.js +46 -40
- package/src/tools.js +19 -2
- package/types.d.ts +78 -137
- package/version.json +1 -1
package/src/manager.js
CHANGED
|
@@ -2,7 +2,7 @@ const assert = require('node:assert')
|
|
|
2
2
|
const EventEmitter = require('node:events')
|
|
3
3
|
const { randomUUID } = require('node:crypto')
|
|
4
4
|
const { serializeError: stringify } = require('serialize-error')
|
|
5
|
-
const { delay } = require('./tools')
|
|
5
|
+
const { delay, resolveWithinSeconds } = require('./tools')
|
|
6
6
|
const Attorney = require('./attorney')
|
|
7
7
|
const Worker = require('./worker')
|
|
8
8
|
const plans = require('./plans')
|
|
@@ -17,61 +17,22 @@ const events = {
|
|
|
17
17
|
wip: 'wip'
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
const resolveWithinSeconds = async (promise, seconds) => {
|
|
21
|
-
const timeout = Math.max(1, seconds) * 1000
|
|
22
|
-
const reject = delay(timeout, `handler execution exceeded ${timeout}ms`)
|
|
23
|
-
|
|
24
|
-
let result
|
|
25
|
-
|
|
26
|
-
try {
|
|
27
|
-
result = await Promise.race([promise, reject])
|
|
28
|
-
} finally {
|
|
29
|
-
reject.abort()
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
return result
|
|
33
|
-
}
|
|
34
|
-
|
|
35
20
|
class Manager extends EventEmitter {
|
|
36
21
|
constructor (db, config) {
|
|
37
22
|
super()
|
|
38
23
|
|
|
39
24
|
this.config = config
|
|
40
25
|
this.db = db
|
|
41
|
-
|
|
42
|
-
this.events = events
|
|
43
26
|
this.wipTs = Date.now()
|
|
44
27
|
this.workers = new Map()
|
|
28
|
+
this.queues = null
|
|
45
29
|
|
|
46
|
-
this.
|
|
47
|
-
this.insertJobCommand = plans.insertJob(config.schema)
|
|
48
|
-
this.insertJobsCommand = plans.insertJobs(config.schema)
|
|
49
|
-
this.completeJobsCommand = plans.completeJobs(config.schema)
|
|
50
|
-
this.cancelJobsCommand = plans.cancelJobs(config.schema)
|
|
51
|
-
this.resumeJobsCommand = plans.resumeJobs(config.schema)
|
|
52
|
-
this.deleteJobsCommand = plans.deleteJobs(config.schema)
|
|
53
|
-
this.retryJobsCommand = plans.retryJobs(config.schema)
|
|
54
|
-
this.failJobsByIdCommand = plans.failJobsById(config.schema)
|
|
55
|
-
this.getJobByIdCommand = plans.getJobById(config.schema)
|
|
56
|
-
this.getArchivedJobByIdCommand = plans.getArchivedJobById(config.schema)
|
|
57
|
-
this.subscribeCommand = plans.subscribe(config.schema)
|
|
58
|
-
this.unsubscribeCommand = plans.unsubscribe(config.schema)
|
|
59
|
-
this.getQueuesCommand = plans.getQueues(config.schema)
|
|
60
|
-
this.getQueueByNameCommand = plans.getQueueByName(config.schema)
|
|
61
|
-
this.getQueuesForEventCommand = plans.getQueuesForEvent(config.schema)
|
|
62
|
-
this.createQueueCommand = plans.createQueue(config.schema)
|
|
63
|
-
this.updateQueueCommand = plans.updateQueue(config.schema)
|
|
64
|
-
this.purgeQueueCommand = plans.purgeQueue(config.schema)
|
|
65
|
-
this.deleteQueueCommand = plans.deleteQueue(config.schema)
|
|
66
|
-
this.clearStorageCommand = plans.clearStorage(config.schema)
|
|
67
|
-
|
|
68
|
-
// exported api to index
|
|
30
|
+
this.events = events
|
|
69
31
|
this.functions = [
|
|
70
32
|
this.complete,
|
|
71
33
|
this.cancel,
|
|
72
34
|
this.resume,
|
|
73
35
|
this.retry,
|
|
74
|
-
this.deleteJob,
|
|
75
36
|
this.fail,
|
|
76
37
|
this.fetch,
|
|
77
38
|
this.work,
|
|
@@ -88,22 +49,56 @@ class Manager extends EventEmitter {
|
|
|
88
49
|
this.createQueue,
|
|
89
50
|
this.updateQueue,
|
|
90
51
|
this.deleteQueue,
|
|
91
|
-
this.
|
|
92
|
-
this.getQueueSize,
|
|
52
|
+
this.getQueueStats,
|
|
93
53
|
this.getQueue,
|
|
94
54
|
this.getQueues,
|
|
95
|
-
this.
|
|
55
|
+
this.deleteQueuedJobs,
|
|
56
|
+
this.deleteStoredJobs,
|
|
57
|
+
this.deleteAllJobs,
|
|
58
|
+
this.deleteJob,
|
|
96
59
|
this.getJobById
|
|
97
60
|
]
|
|
98
61
|
}
|
|
99
62
|
|
|
100
|
-
start () {
|
|
63
|
+
async start () {
|
|
101
64
|
this.stopped = false
|
|
65
|
+
this.queueCacheInterval = setInterval(() => this.onCacheQueues({ emit: true }), this.config.queueCacheIntervalSeconds * 1000)
|
|
66
|
+
await this.onCacheQueues()
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async onCacheQueues ({ emit = false } = {}) {
|
|
70
|
+
try {
|
|
71
|
+
assert(!this.config.__test__throw_queueCache, 'test error')
|
|
72
|
+
const queues = await this.getQueues()
|
|
73
|
+
this.queues = queues.reduce((acc, i) => { acc[i.name] = i; return acc }, {})
|
|
74
|
+
} catch (error) {
|
|
75
|
+
emit && this.emit(events.error, { ...error, message: error.message, stack: error.stack })
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async getQueueCache (name) {
|
|
80
|
+
let queue = this.queues[name]
|
|
81
|
+
|
|
82
|
+
if (queue) {
|
|
83
|
+
return queue
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
queue = await this.getQueue(name)
|
|
87
|
+
|
|
88
|
+
if (!queue) {
|
|
89
|
+
throw new Error(`Queue ${name} does not exist`)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
this.queues[name] = queue
|
|
93
|
+
|
|
94
|
+
return queue
|
|
102
95
|
}
|
|
103
96
|
|
|
104
97
|
async stop () {
|
|
105
98
|
this.stopped = true
|
|
106
99
|
|
|
100
|
+
clearInterval(this.queueCacheInterval)
|
|
101
|
+
|
|
107
102
|
for (const worker of this.workers.values()) {
|
|
108
103
|
if (!INTERNAL_QUEUES[worker.name]) {
|
|
109
104
|
await this.offWork(worker.name)
|
|
@@ -121,7 +116,7 @@ class Manager extends EventEmitter {
|
|
|
121
116
|
}
|
|
122
117
|
|
|
123
118
|
async work (name, ...args) {
|
|
124
|
-
const { options, callback } = Attorney.checkWorkArgs(name, args
|
|
119
|
+
const { options, callback } = Attorney.checkWorkArgs(name, args)
|
|
125
120
|
return await this.watch(name, options, callback)
|
|
126
121
|
}
|
|
127
122
|
|
|
@@ -213,10 +208,10 @@ class Manager extends EventEmitter {
|
|
|
213
208
|
const jobIds = jobs.map(job => job.id)
|
|
214
209
|
|
|
215
210
|
try {
|
|
216
|
-
const result = await resolveWithinSeconds(callback(jobs), maxExpiration)
|
|
217
|
-
this.complete(name, jobIds, jobIds.length === 1 ? result : undefined)
|
|
211
|
+
const result = await resolveWithinSeconds(callback(jobs), maxExpiration, `handler execution exceeded ${maxExpiration}s`)
|
|
212
|
+
await this.complete(name, jobIds, jobIds.length === 1 ? result : undefined)
|
|
218
213
|
} catch (err) {
|
|
219
|
-
this.fail(name, jobIds, err)
|
|
214
|
+
await this.fail(name, jobIds, err)
|
|
220
215
|
}
|
|
221
216
|
|
|
222
217
|
this.emitWip(name)
|
|
@@ -276,27 +271,28 @@ class Manager extends EventEmitter {
|
|
|
276
271
|
async subscribe (event, name) {
|
|
277
272
|
assert(event, 'Missing required argument')
|
|
278
273
|
assert(name, 'Missing required argument')
|
|
279
|
-
|
|
280
|
-
return await this.db.executeSql(
|
|
274
|
+
const sql = plans.subscribe(this.config.schema)
|
|
275
|
+
return await this.db.executeSql(sql, [event, name])
|
|
281
276
|
}
|
|
282
277
|
|
|
283
278
|
async unsubscribe (event, name) {
|
|
284
279
|
assert(event, 'Missing required argument')
|
|
285
280
|
assert(name, 'Missing required argument')
|
|
286
|
-
|
|
287
|
-
return await this.db.executeSql(
|
|
281
|
+
const sql = plans.unsubscribe(this.config.schema)
|
|
282
|
+
return await this.db.executeSql(sql, [event, name])
|
|
288
283
|
}
|
|
289
284
|
|
|
290
285
|
async publish (event, ...args) {
|
|
291
286
|
assert(event, 'Missing required argument')
|
|
292
|
-
|
|
293
|
-
const { rows } = await this.db.executeSql(
|
|
287
|
+
const sql = plans.getQueuesForEvent(this.config.schema)
|
|
288
|
+
const { rows } = await this.db.executeSql(sql, [event])
|
|
294
289
|
|
|
295
290
|
await Promise.allSettled(rows.map(({ name }) => this.send(name, ...args)))
|
|
296
291
|
}
|
|
297
292
|
|
|
298
293
|
async send (...args) {
|
|
299
|
-
const { name, data, options } = Attorney.checkSendArgs(args
|
|
294
|
+
const { name, data, options } = Attorney.checkSendArgs(args)
|
|
295
|
+
|
|
300
296
|
return await this.createJob(name, data, options)
|
|
301
297
|
}
|
|
302
298
|
|
|
@@ -304,7 +300,7 @@ class Manager extends EventEmitter {
|
|
|
304
300
|
options = options ? { ...options } : {}
|
|
305
301
|
options.startAfter = after
|
|
306
302
|
|
|
307
|
-
const result = Attorney.checkSendArgs([name, data, options]
|
|
303
|
+
const result = Attorney.checkSendArgs([name, data, options])
|
|
308
304
|
|
|
309
305
|
return await this.createJob(result.name, result.data, result.options)
|
|
310
306
|
}
|
|
@@ -315,7 +311,7 @@ class Manager extends EventEmitter {
|
|
|
315
311
|
options.singletonNextSlot = false
|
|
316
312
|
options.singletonKey = key
|
|
317
313
|
|
|
318
|
-
const result = Attorney.checkSendArgs([name, data, options]
|
|
314
|
+
const result = Attorney.checkSendArgs([name, data, options])
|
|
319
315
|
|
|
320
316
|
return await this.createJob(result.name, result.data, result.options)
|
|
321
317
|
}
|
|
@@ -326,12 +322,14 @@ class Manager extends EventEmitter {
|
|
|
326
322
|
options.singletonNextSlot = true
|
|
327
323
|
options.singletonKey = key
|
|
328
324
|
|
|
329
|
-
const result = Attorney.checkSendArgs([name, data, options]
|
|
325
|
+
const result = Attorney.checkSendArgs([name, data, options])
|
|
330
326
|
|
|
331
327
|
return await this.createJob(result.name, result.data, result.options)
|
|
332
328
|
}
|
|
333
329
|
|
|
334
|
-
async createJob (name, data, options
|
|
330
|
+
async createJob (name, data, options) {
|
|
331
|
+
const singletonOffset = 0
|
|
332
|
+
|
|
335
333
|
const {
|
|
336
334
|
id = null,
|
|
337
335
|
db: wrapper,
|
|
@@ -339,78 +337,71 @@ class Manager extends EventEmitter {
|
|
|
339
337
|
startAfter,
|
|
340
338
|
singletonKey = null,
|
|
341
339
|
singletonSeconds,
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
340
|
+
singletonNextSlot,
|
|
341
|
+
expireInSeconds,
|
|
342
|
+
deleteAfterSeconds,
|
|
345
343
|
keepUntil,
|
|
346
|
-
keepUntilDefault,
|
|
347
344
|
retryLimit,
|
|
348
|
-
retryLimitDefault,
|
|
349
345
|
retryDelay,
|
|
350
|
-
retryDelayDefault,
|
|
351
346
|
retryBackoff,
|
|
352
|
-
|
|
347
|
+
retryDelayMax
|
|
353
348
|
} = options
|
|
354
349
|
|
|
355
|
-
const
|
|
356
|
-
id,
|
|
357
|
-
name,
|
|
358
|
-
data,
|
|
359
|
-
priority,
|
|
360
|
-
startAfter,
|
|
361
|
-
singletonKey,
|
|
362
|
-
singletonSeconds,
|
|
363
|
-
singletonOffset,
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
retryDelayDefault, // 17
|
|
373
|
-
retryBackoff, // 18
|
|
374
|
-
retryBackoffDefault // 19
|
|
375
|
-
]
|
|
350
|
+
const job = {
|
|
351
|
+
id,
|
|
352
|
+
name,
|
|
353
|
+
data,
|
|
354
|
+
priority,
|
|
355
|
+
startAfter,
|
|
356
|
+
singletonKey,
|
|
357
|
+
singletonSeconds,
|
|
358
|
+
singletonOffset,
|
|
359
|
+
expireInSeconds,
|
|
360
|
+
deleteAfterSeconds,
|
|
361
|
+
keepUntil,
|
|
362
|
+
retryLimit,
|
|
363
|
+
retryDelay,
|
|
364
|
+
retryBackoff,
|
|
365
|
+
retryDelayMax
|
|
366
|
+
}
|
|
376
367
|
|
|
377
368
|
const db = wrapper || this.db
|
|
378
|
-
const { rows } = await db.executeSql(this.insertJobCommand, values)
|
|
379
369
|
|
|
380
|
-
|
|
381
|
-
return rows[0].id
|
|
382
|
-
}
|
|
370
|
+
const { table } = await this.getQueueCache(name)
|
|
383
371
|
|
|
384
|
-
|
|
385
|
-
|
|
372
|
+
const sql = plans.insertJobs(this.config.schema, { table, name, returnId: true })
|
|
373
|
+
|
|
374
|
+
const { rows: try1 } = await db.executeSql(sql, [JSON.stringify([job])])
|
|
375
|
+
|
|
376
|
+
if (try1.length === 1) {
|
|
377
|
+
return try1[0].id
|
|
386
378
|
}
|
|
387
379
|
|
|
388
|
-
|
|
389
|
-
|
|
380
|
+
if (singletonNextSlot) {
|
|
381
|
+
// delay starting by the offset to honor throttling config
|
|
382
|
+
job.startAfter = this.getDebounceStartAfter(singletonSeconds, this.timekeeper.clockSkew)
|
|
383
|
+
job.singletonOffset = singletonSeconds
|
|
390
384
|
|
|
391
|
-
|
|
392
|
-
options.singletonNextSlot = false
|
|
385
|
+
const { rows: try2 } = await db.executeSql(sql, [JSON.stringify([job])])
|
|
393
386
|
|
|
394
|
-
|
|
387
|
+
if (try2.length === 1) {
|
|
388
|
+
return try2[0].id
|
|
389
|
+
}
|
|
390
|
+
}
|
|
395
391
|
|
|
396
|
-
return
|
|
392
|
+
return null
|
|
397
393
|
}
|
|
398
394
|
|
|
399
|
-
async insert (jobs, options = {}) {
|
|
395
|
+
async insert (name, jobs, options = {}) {
|
|
400
396
|
assert(Array.isArray(jobs), 'jobs argument should be an array')
|
|
401
397
|
|
|
402
|
-
const
|
|
398
|
+
const { table } = await this.getQueueCache(name)
|
|
403
399
|
|
|
404
|
-
const
|
|
405
|
-
JSON.stringify(jobs), // 1
|
|
406
|
-
this.config.expireIn, // 2
|
|
407
|
-
this.config.keepUntil, // 3
|
|
408
|
-
this.config.retryLimit, // 4
|
|
409
|
-
this.config.retryDelay, // 5
|
|
410
|
-
this.config.retryBackoff // 6
|
|
411
|
-
]
|
|
400
|
+
const db = this.assertDb(options)
|
|
412
401
|
|
|
413
|
-
const
|
|
402
|
+
const sql = plans.insertJobs(this.config.schema, { table, name, returnId: false })
|
|
403
|
+
|
|
404
|
+
const { rows } = await db.executeSql(sql, [JSON.stringify(jobs)])
|
|
414
405
|
|
|
415
406
|
return (rows.length) ? rows.map(i => i.id) : null
|
|
416
407
|
}
|
|
@@ -434,13 +425,27 @@ class Manager extends EventEmitter {
|
|
|
434
425
|
|
|
435
426
|
async fetch (name, options = {}) {
|
|
436
427
|
Attorney.checkFetchArgs(name, options)
|
|
437
|
-
|
|
438
|
-
const
|
|
428
|
+
|
|
429
|
+
const db = this.assertDb(options)
|
|
430
|
+
|
|
431
|
+
const { table, policy, singletonsActive } = await this.getQueueCache(name)
|
|
432
|
+
|
|
433
|
+
options = {
|
|
434
|
+
...options,
|
|
435
|
+
schema: this.config.schema,
|
|
436
|
+
table,
|
|
437
|
+
name,
|
|
438
|
+
policy,
|
|
439
|
+
limit: options.batchSize,
|
|
440
|
+
ignoreSingletons: singletonsActive
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
const sql = plans.fetchNextJob(options)
|
|
439
444
|
|
|
440
445
|
let result
|
|
441
446
|
|
|
442
447
|
try {
|
|
443
|
-
result = await db.executeSql(
|
|
448
|
+
result = await db.executeSql(sql)
|
|
444
449
|
} catch (err) {
|
|
445
450
|
// errors from fetchquery should only be unique constraint violations
|
|
446
451
|
}
|
|
@@ -480,41 +485,51 @@ class Manager extends EventEmitter {
|
|
|
480
485
|
|
|
481
486
|
async complete (name, id, data, options = {}) {
|
|
482
487
|
Attorney.assertQueueName(name)
|
|
483
|
-
const db =
|
|
488
|
+
const db = this.assertDb(options)
|
|
484
489
|
const ids = this.mapCompletionIdArg(id, 'complete')
|
|
485
|
-
const
|
|
490
|
+
const { table } = await this.getQueueCache(name)
|
|
491
|
+
const sql = plans.completeJobs(this.config.schema, table)
|
|
492
|
+
const result = await db.executeSql(sql, [name, ids, this.mapCompletionDataArg(data)])
|
|
486
493
|
return this.mapCommandResponse(ids, result)
|
|
487
494
|
}
|
|
488
495
|
|
|
489
496
|
async fail (name, id, data, options = {}) {
|
|
490
497
|
Attorney.assertQueueName(name)
|
|
491
|
-
const db =
|
|
498
|
+
const db = this.assertDb(options)
|
|
492
499
|
const ids = this.mapCompletionIdArg(id, 'fail')
|
|
493
|
-
const
|
|
500
|
+
const { table } = await this.getQueueCache(name)
|
|
501
|
+
const sql = plans.failJobsById(this.config.schema, table)
|
|
502
|
+
const result = await db.executeSql(sql, [name, ids, this.mapCompletionDataArg(data)])
|
|
494
503
|
return this.mapCommandResponse(ids, result)
|
|
495
504
|
}
|
|
496
505
|
|
|
497
506
|
async cancel (name, id, options = {}) {
|
|
498
507
|
Attorney.assertQueueName(name)
|
|
499
|
-
const db =
|
|
508
|
+
const db = this.assertDb(options)
|
|
500
509
|
const ids = this.mapCompletionIdArg(id, 'cancel')
|
|
501
|
-
const
|
|
510
|
+
const { table } = await this.getQueueCache(name)
|
|
511
|
+
const sql = plans.cancelJobs(this.config.schema, table)
|
|
512
|
+
const result = await db.executeSql(sql, [name, ids])
|
|
502
513
|
return this.mapCommandResponse(ids, result)
|
|
503
514
|
}
|
|
504
515
|
|
|
505
516
|
async deleteJob (name, id, options = {}) {
|
|
506
517
|
Attorney.assertQueueName(name)
|
|
507
|
-
const db =
|
|
518
|
+
const db = this.assertDb(options)
|
|
508
519
|
const ids = this.mapCompletionIdArg(id, 'deleteJob')
|
|
509
|
-
const
|
|
520
|
+
const { table } = await this.getQueueCache(name)
|
|
521
|
+
const sql = plans.deleteJobsById(this.config.schema, table)
|
|
522
|
+
const result = await db.executeSql(sql, [name, ids])
|
|
510
523
|
return this.mapCommandResponse(ids, result)
|
|
511
524
|
}
|
|
512
525
|
|
|
513
526
|
async resume (name, id, options = {}) {
|
|
514
527
|
Attorney.assertQueueName(name)
|
|
515
|
-
const db =
|
|
528
|
+
const db = this.assertDb(options)
|
|
516
529
|
const ids = this.mapCompletionIdArg(id, 'resume')
|
|
517
|
-
const
|
|
530
|
+
const { table } = await this.getQueueCache(name)
|
|
531
|
+
const sql = plans.resumeJobs(this.config.schema, table)
|
|
532
|
+
const result = await db.executeSql(sql, [name, ids])
|
|
518
533
|
return this.mapCommandResponse(ids, result)
|
|
519
534
|
}
|
|
520
535
|
|
|
@@ -522,7 +537,9 @@ class Manager extends EventEmitter {
|
|
|
522
537
|
Attorney.assertQueueName(name)
|
|
523
538
|
const db = options.db || this.db
|
|
524
539
|
const ids = this.mapCompletionIdArg(id, 'retry')
|
|
525
|
-
const
|
|
540
|
+
const { table } = await this.getQueueCache(name)
|
|
541
|
+
const sql = plans.retryJobs(this.config.schema, table)
|
|
542
|
+
const result = await db.executeSql(sql, [name, ids])
|
|
526
543
|
return this.mapCommandResponse(ids, result)
|
|
527
544
|
}
|
|
528
545
|
|
|
@@ -531,76 +548,62 @@ class Manager extends EventEmitter {
|
|
|
531
548
|
|
|
532
549
|
Attorney.assertQueueName(name)
|
|
533
550
|
|
|
534
|
-
|
|
551
|
+
options.policy = options.policy || QUEUE_POLICIES.standard
|
|
535
552
|
|
|
536
|
-
assert(policy in QUEUE_POLICIES, `${policy} is not a valid queue policy`)
|
|
553
|
+
assert(options.policy in QUEUE_POLICIES, `${options.policy} is not a valid queue policy`)
|
|
537
554
|
|
|
538
|
-
|
|
539
|
-
retryLimit,
|
|
540
|
-
retryDelay,
|
|
541
|
-
retryBackoff,
|
|
542
|
-
expireInSeconds,
|
|
543
|
-
retentionMinutes,
|
|
544
|
-
deadLetter
|
|
545
|
-
} = Attorney.checkQueueArgs(name, options)
|
|
555
|
+
Attorney.validateQueueArgs(options)
|
|
546
556
|
|
|
547
|
-
if (deadLetter) {
|
|
548
|
-
Attorney.assertQueueName(deadLetter)
|
|
557
|
+
if (options.deadLetter) {
|
|
558
|
+
Attorney.assertQueueName(options.deadLetter)
|
|
559
|
+
assert.notStrictEqual(name, options.deadLetter, 'deadLetter cannot be itself')
|
|
560
|
+
await this.getQueueCache(options.deadLetter)
|
|
549
561
|
}
|
|
550
562
|
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
policy,
|
|
554
|
-
retryLimit,
|
|
555
|
-
retryDelay,
|
|
556
|
-
retryBackoff,
|
|
557
|
-
expireInSeconds,
|
|
558
|
-
retentionMinutes,
|
|
559
|
-
deadLetter
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
await this.db.executeSql(this.createQueueCommand, [name, data])
|
|
563
|
+
const sql = plans.createQueue(this.config.schema, name, options)
|
|
564
|
+
await this.db.executeSql(sql)
|
|
563
565
|
}
|
|
564
566
|
|
|
565
|
-
async getQueues () {
|
|
566
|
-
|
|
567
|
+
async getQueues (names) {
|
|
568
|
+
if (names) {
|
|
569
|
+
names = Array.isArray(names) ? names : [names]
|
|
570
|
+
for (const name of names) {
|
|
571
|
+
Attorney.assertQueueName(name)
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
const sql = plans.getQueues(this.config.schema, names)
|
|
576
|
+
const { rows } = await this.db.executeSql(sql)
|
|
567
577
|
return rows
|
|
568
578
|
}
|
|
569
579
|
|
|
570
580
|
async updateQueue (name, options = {}) {
|
|
571
581
|
Attorney.assertQueueName(name)
|
|
572
582
|
|
|
573
|
-
|
|
583
|
+
assert(Object.keys(options).length > 0, 'no properties found to update')
|
|
574
584
|
|
|
575
|
-
|
|
585
|
+
if ('policy' in options) {
|
|
586
|
+
assert(options.policy in QUEUE_POLICIES, `${options.policy} is not a valid queue policy`)
|
|
587
|
+
}
|
|
576
588
|
|
|
577
|
-
|
|
578
|
-
retryLimit,
|
|
579
|
-
retryDelay,
|
|
580
|
-
retryBackoff,
|
|
581
|
-
expireInSeconds,
|
|
582
|
-
retentionMinutes,
|
|
583
|
-
deadLetter
|
|
584
|
-
} = Attorney.checkQueueArgs(name, options)
|
|
589
|
+
Attorney.validateQueueArgs(options)
|
|
585
590
|
|
|
586
|
-
const
|
|
587
|
-
name,
|
|
588
|
-
policy,
|
|
589
|
-
retryLimit,
|
|
590
|
-
retryDelay,
|
|
591
|
-
retryBackoff,
|
|
592
|
-
expireInSeconds,
|
|
593
|
-
retentionMinutes,
|
|
594
|
-
deadLetter
|
|
595
|
-
]
|
|
591
|
+
const { deadLetter } = options
|
|
596
592
|
|
|
597
|
-
|
|
593
|
+
if (deadLetter) {
|
|
594
|
+
Attorney.assertQueueName(deadLetter)
|
|
595
|
+
assert.notStrictEqual(name, deadLetter, 'deadLetter cannot be itself')
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
const sql = plans.updateQueue(this.config.schema, { deadLetter })
|
|
599
|
+
await this.db.executeSql(sql, [name, options])
|
|
598
600
|
}
|
|
599
601
|
|
|
600
602
|
async getQueue (name) {
|
|
601
603
|
Attorney.assertQueueName(name)
|
|
602
604
|
|
|
603
|
-
const
|
|
605
|
+
const sql = plans.getQueues(this.config.schema, [name])
|
|
606
|
+
const { rows } = await this.db.executeSql(sql)
|
|
604
607
|
|
|
605
608
|
return rows[0] || null
|
|
606
609
|
}
|
|
@@ -608,48 +611,79 @@ class Manager extends EventEmitter {
|
|
|
608
611
|
async deleteQueue (name) {
|
|
609
612
|
Attorney.assertQueueName(name)
|
|
610
613
|
|
|
611
|
-
|
|
614
|
+
try {
|
|
615
|
+
await this.getQueueCache(name)
|
|
616
|
+
const sql = plans.deleteQueue(this.config.schema, name)
|
|
617
|
+
await this.db.executeSql(sql)
|
|
618
|
+
} catch {}
|
|
619
|
+
}
|
|
612
620
|
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
}
|
|
621
|
+
async deleteQueuedJobs (name) {
|
|
622
|
+
Attorney.assertQueueName(name)
|
|
623
|
+
const { table } = await this.getQueueCache(name)
|
|
624
|
+
const sql = plans.deleteQueuedJobs(this.config.schema, table)
|
|
625
|
+
await this.db.executeSql(sql, [name])
|
|
616
626
|
}
|
|
617
627
|
|
|
618
|
-
async
|
|
628
|
+
async deleteStoredJobs (name) {
|
|
619
629
|
Attorney.assertQueueName(name)
|
|
620
|
-
await this.
|
|
630
|
+
const { table } = await this.getQueueCache(name)
|
|
631
|
+
const sql = plans.deleteStoredJobs(this.config.schema, table)
|
|
632
|
+
await this.db.executeSql(sql, [name])
|
|
621
633
|
}
|
|
622
634
|
|
|
623
|
-
async
|
|
624
|
-
|
|
635
|
+
async deleteAllJobs (name) {
|
|
636
|
+
Attorney.assertQueueName(name)
|
|
637
|
+
const { table, partition } = await this.getQueueCache(name)
|
|
638
|
+
|
|
639
|
+
if (partition) {
|
|
640
|
+
const sql = plans.deleteAllJobs(this.config.schema, table)
|
|
641
|
+
await this.db.executeSql(sql, [name])
|
|
642
|
+
} else {
|
|
643
|
+
const sql = plans.truncateTable(this.config.schema, table)
|
|
644
|
+
await this.db.executeSql(sql)
|
|
645
|
+
}
|
|
625
646
|
}
|
|
626
647
|
|
|
627
|
-
async
|
|
648
|
+
async getQueueStats (name) {
|
|
628
649
|
Attorney.assertQueueName(name)
|
|
629
650
|
|
|
630
|
-
const
|
|
651
|
+
const { table } = await this.getQueueCache(name)
|
|
652
|
+
|
|
653
|
+
const sql = plans.getQueueStats(this.config.schema, table, [name])
|
|
631
654
|
|
|
632
|
-
const
|
|
655
|
+
const { rows } = await this.db.executeSql(sql)
|
|
633
656
|
|
|
634
|
-
return
|
|
657
|
+
return rows.at(0) || null
|
|
635
658
|
}
|
|
636
659
|
|
|
637
660
|
async getJobById (name, id, options = {}) {
|
|
638
661
|
Attorney.assertQueueName(name)
|
|
639
662
|
|
|
640
|
-
const db =
|
|
663
|
+
const db = this.assertDb(options)
|
|
641
664
|
|
|
642
|
-
const
|
|
665
|
+
const { table } = await this.getQueueCache(name)
|
|
666
|
+
|
|
667
|
+
const sql = plans.getJobById(this.config.schema, table)
|
|
668
|
+
|
|
669
|
+
const result1 = await db.executeSql(sql, [name, id])
|
|
643
670
|
|
|
644
671
|
if (result1?.rows?.length === 1) {
|
|
645
672
|
return result1.rows[0]
|
|
646
|
-
} else if (options.includeArchive) {
|
|
647
|
-
const result2 = await db.executeSql(this.getArchivedJobByIdCommand, [name, id])
|
|
648
|
-
return result2?.rows[0] || null
|
|
649
673
|
} else {
|
|
650
674
|
return null
|
|
651
675
|
}
|
|
652
676
|
}
|
|
677
|
+
|
|
678
|
+
assertDb (options) {
|
|
679
|
+
if (options.db) {
|
|
680
|
+
return options.db
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
assert(this.db._pgbdb && this.db.opened, 'Database connection is not opened')
|
|
684
|
+
|
|
685
|
+
return this.db
|
|
686
|
+
}
|
|
653
687
|
}
|
|
654
688
|
|
|
655
689
|
module.exports = Manager
|