pg-boss 9.0.3 → 10.0.0-beta2
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 +11 -27
- package/package.json +7 -11
- package/src/attorney.js +66 -90
- package/src/boss.js +97 -132
- package/src/contractor.js +16 -1
- package/src/db.js +37 -5
- package/src/index.js +65 -55
- package/src/manager.js +213 -130
- package/src/migrationStore.js +0 -105
- package/src/plans.js +329 -296
- package/src/timekeeper.js +8 -7
- package/src/tools.js +28 -0
- package/src/worker.js +4 -4
- package/types.d.ts +27 -45
- package/version.json +1 -1
package/src/manager.js
CHANGED
|
@@ -1,21 +1,18 @@
|
|
|
1
1
|
const assert = require('assert')
|
|
2
2
|
const EventEmitter = require('events')
|
|
3
|
-
const
|
|
4
|
-
const uuid = require('uuid')
|
|
3
|
+
const { randomUUID } = require('crypto')
|
|
5
4
|
const debounce = require('lodash.debounce')
|
|
6
5
|
const { serializeError: stringify } = require('serialize-error')
|
|
6
|
+
const pMap = require('p-map')
|
|
7
|
+
const { delay } = require('./tools')
|
|
7
8
|
const Attorney = require('./attorney')
|
|
8
9
|
const Worker = require('./worker')
|
|
9
|
-
const
|
|
10
|
-
const pMap = require('p-map')
|
|
10
|
+
const plans = require('./plans')
|
|
11
11
|
|
|
12
|
-
const { QUEUES: BOSS_QUEUES } = require('./boss')
|
|
13
12
|
const { QUEUES: TIMEKEEPER_QUEUES } = require('./timekeeper')
|
|
13
|
+
const { QUEUE_POLICY } = plans
|
|
14
14
|
|
|
15
|
-
const INTERNAL_QUEUES = Object.values(
|
|
16
|
-
|
|
17
|
-
const plans = require('./plans')
|
|
18
|
-
const { COMPLETION_JOB_PREFIX, SINGLETON_QUEUE_KEY } = plans
|
|
15
|
+
const INTERNAL_QUEUES = Object.values(TIMEKEEPER_QUEUES).reduce((acc, i) => ({ ...acc, [i]: i }), {})
|
|
19
16
|
|
|
20
17
|
const WIP_EVENT_INTERVAL = 2000
|
|
21
18
|
const WIP_DEBOUNCE_OPTIONS = { leading: true, trailing: true, maxWait: WIP_EVENT_INTERVAL }
|
|
@@ -27,16 +24,14 @@ const events = {
|
|
|
27
24
|
|
|
28
25
|
const resolveWithinSeconds = async (promise, seconds) => {
|
|
29
26
|
const timeout = Math.max(1, seconds) * 1000
|
|
30
|
-
const reject = delay
|
|
27
|
+
const reject = delay(timeout, `handler execution exceeded ${timeout}ms`)
|
|
31
28
|
|
|
32
29
|
let result
|
|
33
30
|
|
|
34
31
|
try {
|
|
35
32
|
result = await Promise.race([promise, reject])
|
|
36
33
|
} finally {
|
|
37
|
-
|
|
38
|
-
reject.clear()
|
|
39
|
-
} catch {}
|
|
34
|
+
reject.abort()
|
|
40
35
|
}
|
|
41
36
|
|
|
42
37
|
return result
|
|
@@ -58,7 +53,7 @@ class Manager extends EventEmitter {
|
|
|
58
53
|
this.completeJobsCommand = plans.completeJobs(config.schema)
|
|
59
54
|
this.cancelJobsCommand = plans.cancelJobs(config.schema)
|
|
60
55
|
this.resumeJobsCommand = plans.resumeJobs(config.schema)
|
|
61
|
-
this.
|
|
56
|
+
this.failJobsByIdCommand = plans.failJobsById(config.schema)
|
|
62
57
|
this.getJobByIdCommand = plans.getJobById(config.schema)
|
|
63
58
|
this.getArchivedJobByIdCommand = plans.getArchivedJobById(config.schema)
|
|
64
59
|
this.subscribeCommand = plans.subscribe(config.schema)
|
|
@@ -72,12 +67,9 @@ class Manager extends EventEmitter {
|
|
|
72
67
|
this.resume,
|
|
73
68
|
this.fail,
|
|
74
69
|
this.fetch,
|
|
75
|
-
this.fetchCompleted,
|
|
76
70
|
this.work,
|
|
77
71
|
this.offWork,
|
|
78
72
|
this.notifyWorker,
|
|
79
|
-
this.onComplete,
|
|
80
|
-
this.offComplete,
|
|
81
73
|
this.publish,
|
|
82
74
|
this.subscribe,
|
|
83
75
|
this.unsubscribe,
|
|
@@ -85,13 +77,14 @@ class Manager extends EventEmitter {
|
|
|
85
77
|
this.send,
|
|
86
78
|
this.sendDebounced,
|
|
87
79
|
this.sendThrottled,
|
|
88
|
-
this.sendOnce,
|
|
89
80
|
this.sendAfter,
|
|
90
|
-
this.
|
|
81
|
+
this.createQueue,
|
|
82
|
+
this.updateQueue,
|
|
83
|
+
this.getQueue,
|
|
91
84
|
this.deleteQueue,
|
|
92
|
-
this.
|
|
93
|
-
this.clearStorage,
|
|
85
|
+
this.purgeQueue,
|
|
94
86
|
this.getQueueSize,
|
|
87
|
+
this.clearStorage,
|
|
95
88
|
this.getJobById
|
|
96
89
|
]
|
|
97
90
|
|
|
@@ -99,27 +92,31 @@ class Manager extends EventEmitter {
|
|
|
99
92
|
}
|
|
100
93
|
|
|
101
94
|
start () {
|
|
102
|
-
this.
|
|
95
|
+
this.stopped = false
|
|
103
96
|
}
|
|
104
97
|
|
|
105
98
|
async stop () {
|
|
106
|
-
this.
|
|
99
|
+
this.stopped = true
|
|
107
100
|
|
|
108
|
-
for (const
|
|
109
|
-
if (!INTERNAL_QUEUES[
|
|
110
|
-
await this.offWork(
|
|
101
|
+
for (const worker of this.workers.values()) {
|
|
102
|
+
if (!INTERNAL_QUEUES[worker.name]) {
|
|
103
|
+
await this.offWork(worker.name)
|
|
111
104
|
}
|
|
112
105
|
}
|
|
113
106
|
}
|
|
114
107
|
|
|
115
|
-
async
|
|
116
|
-
const
|
|
117
|
-
|
|
108
|
+
async failWip () {
|
|
109
|
+
for (const worker of this.workers.values()) {
|
|
110
|
+
const jobIds = worker.jobs.map(j => j.id)
|
|
111
|
+
if (jobIds.length) {
|
|
112
|
+
await this.fail(worker.name, jobIds, 'pg-boss shut down while active')
|
|
113
|
+
}
|
|
114
|
+
}
|
|
118
115
|
}
|
|
119
116
|
|
|
120
|
-
async
|
|
117
|
+
async work (name, ...args) {
|
|
121
118
|
const { options, callback } = Attorney.checkWorkArgs(name, args, this.config)
|
|
122
|
-
return await this.watch(
|
|
119
|
+
return await this.watch(name, options, callback)
|
|
123
120
|
}
|
|
124
121
|
|
|
125
122
|
addWorker (worker) {
|
|
@@ -175,8 +172,8 @@ class Manager extends EventEmitter {
|
|
|
175
172
|
}
|
|
176
173
|
|
|
177
174
|
async watch (name, options, callback) {
|
|
178
|
-
if (this.
|
|
179
|
-
throw new Error('Workers are disabled. pg-boss is
|
|
175
|
+
if (this.stopped) {
|
|
176
|
+
throw new Error('Workers are disabled. pg-boss is stopped')
|
|
180
177
|
}
|
|
181
178
|
|
|
182
179
|
const {
|
|
@@ -186,10 +183,10 @@ class Manager extends EventEmitter {
|
|
|
186
183
|
teamConcurrency = 1,
|
|
187
184
|
teamRefill: refill = false,
|
|
188
185
|
includeMetadata = false,
|
|
189
|
-
|
|
186
|
+
priority = true
|
|
190
187
|
} = options
|
|
191
188
|
|
|
192
|
-
const id =
|
|
189
|
+
const id = randomUUID({ disableEntropyCache: true })
|
|
193
190
|
|
|
194
191
|
let queueSize = 0
|
|
195
192
|
|
|
@@ -210,7 +207,7 @@ class Manager extends EventEmitter {
|
|
|
210
207
|
createTeamRefillPromise()
|
|
211
208
|
}
|
|
212
209
|
|
|
213
|
-
const fetch = () => this.fetch(name, batchSize || (teamSize - queueSize), { includeMetadata,
|
|
210
|
+
const fetch = () => this.fetch(name, batchSize || (teamSize - queueSize), { includeMetadata, priority })
|
|
214
211
|
|
|
215
212
|
const onFetch = async (jobs) => {
|
|
216
213
|
if (this.config.__test__throw_worker) {
|
|
@@ -223,8 +220,8 @@ class Manager extends EventEmitter {
|
|
|
223
220
|
const maxExpiration = jobs.reduce((acc, i) => Math.max(acc, i.expire_in_seconds), 0)
|
|
224
221
|
|
|
225
222
|
await resolveWithinSeconds(Promise.all([callback(jobs)]), maxExpiration)
|
|
226
|
-
.then(() => this.complete(jobs.map(job => job.id)))
|
|
227
|
-
.catch(err => this.fail(jobs.map(job => job.id), err))
|
|
223
|
+
.then(() => this.complete(name, jobs.map(job => job.id)))
|
|
224
|
+
.catch(err => this.fail(name, jobs.map(job => job.id), err))
|
|
228
225
|
} else {
|
|
229
226
|
if (refill) {
|
|
230
227
|
queueSize += jobs.length || 1
|
|
@@ -232,8 +229,8 @@ class Manager extends EventEmitter {
|
|
|
232
229
|
|
|
233
230
|
const allTeamPromise = pMap(jobs, job =>
|
|
234
231
|
resolveWithinSeconds(callback(job), job.expire_in_seconds)
|
|
235
|
-
.then(result => this.complete(job.id, result))
|
|
236
|
-
.catch(err => this.fail(job.id, err))
|
|
232
|
+
.then(result => this.complete(name, job.id, result))
|
|
233
|
+
.catch(err => this.fail(name, job.id, err))
|
|
237
234
|
.then(() => refill ? onRefill() : null)
|
|
238
235
|
, { concurrency: teamConcurrency }
|
|
239
236
|
).catch(() => {}) // allow promises & non-promises to live together in harmony
|
|
@@ -329,39 +326,11 @@ class Manager extends EventEmitter {
|
|
|
329
326
|
return await Promise.all(result.rows.map(({ name }) => this.send(name, ...args)))
|
|
330
327
|
}
|
|
331
328
|
|
|
332
|
-
async offComplete (value) {
|
|
333
|
-
if (typeof value === 'string') {
|
|
334
|
-
value = COMPLETION_JOB_PREFIX + value
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
return await this.offWork(value)
|
|
338
|
-
}
|
|
339
|
-
|
|
340
329
|
async send (...args) {
|
|
341
330
|
const { name, data, options } = Attorney.checkSendArgs(args, this.config)
|
|
342
331
|
return await this.createJob(name, data, options)
|
|
343
332
|
}
|
|
344
333
|
|
|
345
|
-
async sendOnce (name, data, options, key) {
|
|
346
|
-
options = options ? { ...options } : {}
|
|
347
|
-
|
|
348
|
-
options.singletonKey = key || name
|
|
349
|
-
|
|
350
|
-
const result = Attorney.checkSendArgs([name, data, options], this.config)
|
|
351
|
-
|
|
352
|
-
return await this.createJob(result.name, result.data, result.options)
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
async sendSingleton (name, data, options) {
|
|
356
|
-
options = options ? { ...options } : {}
|
|
357
|
-
|
|
358
|
-
options.singletonKey = SINGLETON_QUEUE_KEY
|
|
359
|
-
|
|
360
|
-
const result = Attorney.checkSendArgs([name, data, options], this.config)
|
|
361
|
-
|
|
362
|
-
return await this.createJob(result.name, result.data, result.options)
|
|
363
|
-
}
|
|
364
|
-
|
|
365
334
|
async sendAfter (name, data, options, after) {
|
|
366
335
|
options = options ? { ...options } : {}
|
|
367
336
|
options.startAfter = after
|
|
@@ -395,37 +364,47 @@ class Manager extends EventEmitter {
|
|
|
395
364
|
|
|
396
365
|
async createJob (name, data, options, singletonOffset = 0) {
|
|
397
366
|
const {
|
|
367
|
+
id = null,
|
|
398
368
|
db: wrapper,
|
|
399
|
-
expireIn,
|
|
400
369
|
priority,
|
|
401
370
|
startAfter,
|
|
402
|
-
keepUntil,
|
|
403
371
|
singletonKey = null,
|
|
404
372
|
singletonSeconds,
|
|
405
|
-
|
|
373
|
+
deadLetter = null,
|
|
374
|
+
expireIn,
|
|
375
|
+
expireInDefault,
|
|
376
|
+
keepUntil,
|
|
377
|
+
keepUntilDefault,
|
|
406
378
|
retryLimit,
|
|
379
|
+
retryLimitDefault,
|
|
407
380
|
retryDelay,
|
|
408
|
-
|
|
381
|
+
retryDelayDefault,
|
|
382
|
+
retryBackoff,
|
|
383
|
+
retryBackoffDefault
|
|
409
384
|
} = options
|
|
410
385
|
|
|
411
|
-
const id = uuid[this.config.uuid]()
|
|
412
|
-
|
|
413
386
|
const values = [
|
|
414
387
|
id, // 1
|
|
415
388
|
name, // 2
|
|
416
|
-
|
|
417
|
-
|
|
389
|
+
data, // 3
|
|
390
|
+
priority, // 4
|
|
418
391
|
startAfter, // 5
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
392
|
+
singletonKey, // 6
|
|
393
|
+
singletonSeconds, // 7
|
|
394
|
+
singletonOffset, // 8
|
|
395
|
+
deadLetter, // 9
|
|
396
|
+
expireIn, // 10
|
|
397
|
+
expireInDefault, // 11
|
|
398
|
+
keepUntil, // 12
|
|
399
|
+
keepUntilDefault, // 13
|
|
400
|
+
retryLimit, // 14
|
|
401
|
+
retryLimitDefault, // 15
|
|
402
|
+
retryDelay, // 16
|
|
403
|
+
retryDelayDefault, // 17
|
|
404
|
+
retryBackoff, // 18
|
|
405
|
+
retryBackoffDefault // 19
|
|
428
406
|
]
|
|
407
|
+
|
|
429
408
|
const db = wrapper || this.db
|
|
430
409
|
const result = await db.executeSql(this.insertJobCommand, values)
|
|
431
410
|
|
|
@@ -449,11 +428,20 @@ class Manager extends EventEmitter {
|
|
|
449
428
|
}
|
|
450
429
|
|
|
451
430
|
async insert (jobs, options = {}) {
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
const
|
|
455
|
-
|
|
456
|
-
|
|
431
|
+
assert(Array.isArray(jobs), 'jobs argument should be an array')
|
|
432
|
+
|
|
433
|
+
const db = options.db || this.db
|
|
434
|
+
|
|
435
|
+
const params = [
|
|
436
|
+
JSON.stringify(jobs), // 1
|
|
437
|
+
this.config.expireIn, // 2
|
|
438
|
+
this.config.keepUntil, // 3
|
|
439
|
+
this.config.retryLimit, // 4
|
|
440
|
+
this.config.retryDelay, // 5
|
|
441
|
+
this.config.retryBackoff // 6
|
|
442
|
+
]
|
|
443
|
+
|
|
444
|
+
return await db.executeSql(this.insertJobsCommand, params)
|
|
457
445
|
}
|
|
458
446
|
|
|
459
447
|
getDebounceStartAfter (singletonSeconds, clockOffset) {
|
|
@@ -476,25 +464,15 @@ class Manager extends EventEmitter {
|
|
|
476
464
|
async fetch (name, batchSize, options = {}) {
|
|
477
465
|
const values = Attorney.checkFetchArgs(name, batchSize, options)
|
|
478
466
|
const db = options.db || this.db
|
|
479
|
-
const
|
|
467
|
+
const nextJobSql = this.nextJobCommand({ ...options })
|
|
480
468
|
const statementValues = [values.name, batchSize || 1]
|
|
481
469
|
|
|
482
470
|
let result
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
// eslint-disable-next-line no-unused-vars
|
|
489
|
-
const [_begin, _setLocal, fetchResult, _commit] = await db.executeSql([
|
|
490
|
-
'BEGIN',
|
|
491
|
-
'SET LOCAL jit = OFF', // JIT can slow things down significantly
|
|
492
|
-
fetchQuery,
|
|
493
|
-
'COMMIT'
|
|
494
|
-
].join(';\n'))
|
|
495
|
-
result = fetchResult
|
|
496
|
-
} else {
|
|
497
|
-
result = await db.executeSql(preparedStatement, statementValues)
|
|
471
|
+
|
|
472
|
+
try {
|
|
473
|
+
result = await db.executeSql(nextJobSql, statementValues)
|
|
474
|
+
} catch (err) {
|
|
475
|
+
// errors from fetchquery should only be unique constraint violations
|
|
498
476
|
}
|
|
499
477
|
|
|
500
478
|
if (!result || result.rows.length === 0) {
|
|
@@ -504,10 +482,6 @@ class Manager extends EventEmitter {
|
|
|
504
482
|
return result.rows.length === 1 && !batchSize ? result.rows[0] : result.rows
|
|
505
483
|
}
|
|
506
484
|
|
|
507
|
-
async fetchCompleted (name, batchSize, options = {}) {
|
|
508
|
-
return await this.fetch(COMPLETION_JOB_PREFIX + name, batchSize, options)
|
|
509
|
-
}
|
|
510
|
-
|
|
511
485
|
mapCompletionIdArg (id, funcName) {
|
|
512
486
|
const errorMessage = `${funcName}() requires an id`
|
|
513
487
|
|
|
@@ -538,45 +512,154 @@ class Manager extends EventEmitter {
|
|
|
538
512
|
}
|
|
539
513
|
}
|
|
540
514
|
|
|
541
|
-
async complete (id, data, options = {}) {
|
|
515
|
+
async complete (name, id, data, options = {}) {
|
|
516
|
+
assert(name, 'Missing queue name argument')
|
|
542
517
|
const db = options.db || this.db
|
|
543
518
|
const ids = this.mapCompletionIdArg(id, 'complete')
|
|
544
|
-
const result = await db.executeSql(this.completeJobsCommand, [ids, this.mapCompletionDataArg(data)])
|
|
519
|
+
const result = await db.executeSql(this.completeJobsCommand, [name, ids, this.mapCompletionDataArg(data)])
|
|
545
520
|
return this.mapCompletionResponse(ids, result)
|
|
546
521
|
}
|
|
547
522
|
|
|
548
|
-
async fail (id, data, options = {}) {
|
|
523
|
+
async fail (name, id, data, options = {}) {
|
|
524
|
+
assert(name, 'Missing queue name argument')
|
|
549
525
|
const db = options.db || this.db
|
|
550
526
|
const ids = this.mapCompletionIdArg(id, 'fail')
|
|
551
|
-
const result = await db.executeSql(this.
|
|
527
|
+
const result = await db.executeSql(this.failJobsByIdCommand, [name, ids, this.mapCompletionDataArg(data)])
|
|
552
528
|
return this.mapCompletionResponse(ids, result)
|
|
553
529
|
}
|
|
554
530
|
|
|
555
|
-
async cancel (id, options = {}) {
|
|
531
|
+
async cancel (name, id, options = {}) {
|
|
532
|
+
assert(name, 'Missing queue name argument')
|
|
556
533
|
const db = options.db || this.db
|
|
557
534
|
const ids = this.mapCompletionIdArg(id, 'cancel')
|
|
558
|
-
const result = await db.executeSql(this.cancelJobsCommand, [ids])
|
|
535
|
+
const result = await db.executeSql(this.cancelJobsCommand, [name, ids])
|
|
559
536
|
return this.mapCompletionResponse(ids, result)
|
|
560
537
|
}
|
|
561
538
|
|
|
562
|
-
async resume (id, options = {}) {
|
|
539
|
+
async resume (name, id, options = {}) {
|
|
540
|
+
assert(name, 'Missing queue name argument')
|
|
563
541
|
const db = options.db || this.db
|
|
564
542
|
const ids = this.mapCompletionIdArg(id, 'resume')
|
|
565
|
-
const result = await db.executeSql(this.resumeJobsCommand, [ids])
|
|
543
|
+
const result = await db.executeSql(this.resumeJobsCommand, [name, ids])
|
|
566
544
|
return this.mapCompletionResponse(ids, result)
|
|
567
545
|
}
|
|
568
546
|
|
|
569
|
-
async
|
|
570
|
-
assert(
|
|
571
|
-
|
|
572
|
-
const
|
|
573
|
-
|
|
547
|
+
async createQueue (name, options = {}) {
|
|
548
|
+
assert(name, 'Missing queue name argument')
|
|
549
|
+
|
|
550
|
+
const { policy = QUEUE_POLICY.standard } = options
|
|
551
|
+
|
|
552
|
+
assert(policy in QUEUE_POLICY, `${policy} is not a valid queue policy`)
|
|
553
|
+
|
|
554
|
+
const {
|
|
555
|
+
retryLimit,
|
|
556
|
+
retryDelay,
|
|
557
|
+
retryBackoff,
|
|
558
|
+
expireInSeconds,
|
|
559
|
+
retentionMinutes,
|
|
560
|
+
deadLetter
|
|
561
|
+
} = Attorney.checkQueueArgs(name, options)
|
|
562
|
+
|
|
563
|
+
const paritionSql = plans.partitionCreateJobName(this.config.schema, name)
|
|
564
|
+
|
|
565
|
+
await this.db.executeSql(paritionSql)
|
|
566
|
+
|
|
567
|
+
const sql = plans.createQueue(this.config.schema, name)
|
|
568
|
+
|
|
569
|
+
const params = [
|
|
570
|
+
name,
|
|
571
|
+
policy,
|
|
572
|
+
retryLimit,
|
|
573
|
+
retryDelay,
|
|
574
|
+
retryBackoff,
|
|
575
|
+
expireInSeconds,
|
|
576
|
+
retentionMinutes,
|
|
577
|
+
deadLetter
|
|
578
|
+
]
|
|
579
|
+
|
|
580
|
+
await this.db.executeSql(sql, params)
|
|
574
581
|
}
|
|
575
582
|
|
|
576
|
-
async
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
583
|
+
async updateQueue (name, options = {}) {
|
|
584
|
+
assert(name, 'Missing queue name argument')
|
|
585
|
+
|
|
586
|
+
const {
|
|
587
|
+
retryLimit,
|
|
588
|
+
retryDelay,
|
|
589
|
+
retryBackoff,
|
|
590
|
+
expireInSeconds,
|
|
591
|
+
retentionMinutes,
|
|
592
|
+
deadLetter
|
|
593
|
+
} = Attorney.checkQueueArgs(name, options)
|
|
594
|
+
|
|
595
|
+
const sql = plans.updateQueue(this.config.schema)
|
|
596
|
+
|
|
597
|
+
const params = [
|
|
598
|
+
name,
|
|
599
|
+
retryLimit,
|
|
600
|
+
retryDelay,
|
|
601
|
+
retryBackoff,
|
|
602
|
+
expireInSeconds,
|
|
603
|
+
retentionMinutes,
|
|
604
|
+
deadLetter
|
|
605
|
+
]
|
|
606
|
+
|
|
607
|
+
await this.db.executeSql(sql, params)
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
async getQueue (name) {
|
|
611
|
+
assert(name, 'Missing queue name argument')
|
|
612
|
+
|
|
613
|
+
const sql = plans.getQueueByName(this.config.schema)
|
|
614
|
+
const result = await this.db.executeSql(sql, [name])
|
|
615
|
+
|
|
616
|
+
if (result.rows.length === 0) {
|
|
617
|
+
return null
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
const {
|
|
621
|
+
policy,
|
|
622
|
+
retry_limit: retryLimit,
|
|
623
|
+
retry_delay: retryDelay,
|
|
624
|
+
retry_backoff: retryBackoff,
|
|
625
|
+
expire_seconds: expireInSeconds,
|
|
626
|
+
retention_minutes: retentionMinutes,
|
|
627
|
+
dead_letter: deadLetter
|
|
628
|
+
} = result.rows[0]
|
|
629
|
+
|
|
630
|
+
return {
|
|
631
|
+
name,
|
|
632
|
+
policy,
|
|
633
|
+
retryLimit,
|
|
634
|
+
retryDelay,
|
|
635
|
+
retryBackoff,
|
|
636
|
+
expireInSeconds,
|
|
637
|
+
retentionMinutes,
|
|
638
|
+
deadLetter
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
async deleteQueue (name) {
|
|
643
|
+
assert(name, 'Missing queue name argument')
|
|
644
|
+
|
|
645
|
+
const queueSql = plans.getQueueByName(this.config.schema)
|
|
646
|
+
const result = await this.db.executeSql(queueSql, [name])
|
|
647
|
+
|
|
648
|
+
if (result?.rows?.length) {
|
|
649
|
+
Attorney.assertPostgresObjectName(name)
|
|
650
|
+
const sql = plans.dropJobTablePartition(this.config.schema, name)
|
|
651
|
+
await this.db.executeSql(sql)
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
const sql = plans.deleteQueueRecords(this.config.schema)
|
|
655
|
+
const result2 = await this.db.executeSql(sql, [name])
|
|
656
|
+
return result2?.rowCount || null
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
async purgeQueue (queue) {
|
|
660
|
+
assert(queue, 'Missing queue name argument')
|
|
661
|
+
const sql = plans.purgeQueue(this.config.schema)
|
|
662
|
+
await this.db.executeSql(sql, [queue])
|
|
580
663
|
}
|
|
581
664
|
|
|
582
665
|
async clearStorage () {
|
|
@@ -594,15 +677,15 @@ class Manager extends EventEmitter {
|
|
|
594
677
|
return result ? parseFloat(result.rows[0].count) : null
|
|
595
678
|
}
|
|
596
679
|
|
|
597
|
-
async getJobById (id, options = {}) {
|
|
680
|
+
async getJobById (queue, id, options = {}) {
|
|
598
681
|
const db = options.db || this.db
|
|
599
|
-
const result1 = await db.executeSql(this.getJobByIdCommand, [id])
|
|
682
|
+
const result1 = await db.executeSql(this.getJobByIdCommand, [queue, id])
|
|
600
683
|
|
|
601
684
|
if (result1 && result1.rows && result1.rows.length === 1) {
|
|
602
685
|
return result1.rows[0]
|
|
603
686
|
}
|
|
604
687
|
|
|
605
|
-
const result2 = await db.executeSql(this.getArchivedJobByIdCommand, [id])
|
|
688
|
+
const result2 = await db.executeSql(this.getArchivedJobByIdCommand, [queue, id])
|
|
606
689
|
|
|
607
690
|
if (result2 && result2.rows && result2.rows.length === 1) {
|
|
608
691
|
return result2.rows[0]
|
package/src/migrationStore.js
CHANGED
|
@@ -64,110 +64,5 @@ function migrate (value, version, migrations) {
|
|
|
64
64
|
|
|
65
65
|
function getAll (schema) {
|
|
66
66
|
return [
|
|
67
|
-
{
|
|
68
|
-
release: '7.4.0',
|
|
69
|
-
version: 20,
|
|
70
|
-
previous: 19,
|
|
71
|
-
install: [
|
|
72
|
-
`DROP INDEX ${schema}.job_singletonKey`,
|
|
73
|
-
`DROP INDEX ${schema}.job_singleton_queue`,
|
|
74
|
-
`CREATE UNIQUE INDEX job_singletonKey ON ${schema}.job (name, singletonKey) WHERE state < 'completed' AND singletonOn IS NULL AND NOT singletonKey LIKE '\\_\\_pgboss\\_\\_singleton\\_queue%'`,
|
|
75
|
-
`CREATE UNIQUE INDEX job_singleton_queue ON ${schema}.job (name, singletonKey) WHERE state < 'active' AND singletonOn IS NULL AND singletonKey LIKE '\\_\\_pgboss\\_\\_singleton\\_queue%'`
|
|
76
|
-
],
|
|
77
|
-
uninstall: [
|
|
78
|
-
`DROP INDEX ${schema}.job_singletonKey`,
|
|
79
|
-
`DROP INDEX ${schema}.job_singleton_queue`,
|
|
80
|
-
`CREATE UNIQUE INDEX job_singletonKey ON ${schema}.job (name, singletonKey) WHERE state < 'completed' AND singletonOn IS NULL AND NOT singletonKey = '__pgboss__singleton_queue'`,
|
|
81
|
-
`CREATE UNIQUE INDEX job_singleton_queue ON ${schema}.job (name, singletonKey) WHERE state < 'active' AND singletonOn IS NULL AND singletonKey = '__pgboss__singleton_queue'`
|
|
82
|
-
]
|
|
83
|
-
},
|
|
84
|
-
{
|
|
85
|
-
release: '7.0.0',
|
|
86
|
-
version: 19,
|
|
87
|
-
previous: 18,
|
|
88
|
-
install: [
|
|
89
|
-
`CREATE TABLE ${schema}.subscription (
|
|
90
|
-
event text not null,
|
|
91
|
-
name text not null,
|
|
92
|
-
created_on timestamp with time zone not null default now(),
|
|
93
|
-
updated_on timestamp with time zone not null default now(),
|
|
94
|
-
PRIMARY KEY(event, name)
|
|
95
|
-
)`
|
|
96
|
-
],
|
|
97
|
-
uninstall: [
|
|
98
|
-
`DROP TABLE ${schema}.subscription`
|
|
99
|
-
]
|
|
100
|
-
},
|
|
101
|
-
{
|
|
102
|
-
release: '6.1.1',
|
|
103
|
-
version: 18,
|
|
104
|
-
previous: 17,
|
|
105
|
-
install: [
|
|
106
|
-
`ALTER TABLE ${schema}.job ALTER COLUMN on_complete SET DEFAULT false`
|
|
107
|
-
]
|
|
108
|
-
},
|
|
109
|
-
{
|
|
110
|
-
release: '6.0.0',
|
|
111
|
-
version: 17,
|
|
112
|
-
previous: 16,
|
|
113
|
-
install: [
|
|
114
|
-
`DROP INDEX ${schema}.job_singletonKey`,
|
|
115
|
-
`CREATE UNIQUE INDEX job_singletonKey ON ${schema}.job (name, singletonKey) WHERE state < 'completed' AND singletonOn IS NULL AND NOT singletonKey = '__pgboss__singleton_queue'`,
|
|
116
|
-
`CREATE UNIQUE INDEX job_singleton_queue ON ${schema}.job (name, singletonKey) WHERE state < 'active' AND singletonOn IS NULL AND singletonKey = '__pgboss__singleton_queue'`,
|
|
117
|
-
`CREATE INDEX IF NOT EXISTS job_fetch ON ${schema}.job (name text_pattern_ops, startAfter) WHERE state < 'active'`,
|
|
118
|
-
`ALTER TABLE ${schema}.job ADD output jsonb`,
|
|
119
|
-
`ALTER TABLE ${schema}.archive ADD output jsonb`,
|
|
120
|
-
`ALTER TABLE ${schema}.job ALTER COLUMN on_complete SET DEFAULT false`,
|
|
121
|
-
`ALTER TABLE ${schema}.job ALTER COLUMN keepuntil SET DEFAULT now() + interval '14 days'`
|
|
122
|
-
],
|
|
123
|
-
uninstall: [
|
|
124
|
-
`DROP INDEX ${schema}.job_fetch`,
|
|
125
|
-
`DROP INDEX ${schema}.job_singleton_queue`,
|
|
126
|
-
`DROP INDEX ${schema}.job_singletonKey`,
|
|
127
|
-
`CREATE UNIQUE INDEX job_singletonKey ON ${schema}.job (name, singletonKey) WHERE state < 'completed' AND singletonOn IS NULL`,
|
|
128
|
-
`ALTER TABLE ${schema}.job DROP COLUMN output`,
|
|
129
|
-
`ALTER TABLE ${schema}.archive DROP COLUMN output`,
|
|
130
|
-
`ALTER TABLE ${schema}.job ALTER COLUMN on_complete SET DEFAULT true`,
|
|
131
|
-
`ALTER TABLE ${schema}.job ALTER COLUMN keepuntil SET DEFAULT now() + interval '30 days'`
|
|
132
|
-
]
|
|
133
|
-
},
|
|
134
|
-
{
|
|
135
|
-
release: '5.2.0',
|
|
136
|
-
version: 16,
|
|
137
|
-
previous: 15,
|
|
138
|
-
install: [
|
|
139
|
-
`ALTER TABLE ${schema}.job ADD on_complete boolean`,
|
|
140
|
-
`UPDATE ${schema}.job SET on_complete = true`,
|
|
141
|
-
`ALTER TABLE ${schema}.job ALTER COLUMN on_complete SET DEFAULT true`,
|
|
142
|
-
`ALTER TABLE ${schema}.job ALTER COLUMN on_complete SET NOT NULL`,
|
|
143
|
-
`ALTER TABLE ${schema}.archive ADD on_complete boolean`
|
|
144
|
-
],
|
|
145
|
-
uninstall: [
|
|
146
|
-
`ALTER TABLE ${schema}.job DROP COLUMN on_complete`,
|
|
147
|
-
`ALTER TABLE ${schema}.archive DROP COLUMN on_complete`
|
|
148
|
-
]
|
|
149
|
-
},
|
|
150
|
-
{
|
|
151
|
-
release: '5.0.6',
|
|
152
|
-
version: 15,
|
|
153
|
-
previous: 14,
|
|
154
|
-
install: [
|
|
155
|
-
`ALTER TABLE ${schema}.version ADD cron_on timestamp with time zone`
|
|
156
|
-
],
|
|
157
|
-
uninstall: [
|
|
158
|
-
`ALTER TABLE ${schema}.version DROP COLUMN cron_on`
|
|
159
|
-
]
|
|
160
|
-
},
|
|
161
|
-
{
|
|
162
|
-
release: '5.0.0',
|
|
163
|
-
version: 14,
|
|
164
|
-
previous: 13,
|
|
165
|
-
install: [
|
|
166
|
-
`ALTER TABLE ${schema}.version ADD maintained_on timestamp with time zone`
|
|
167
|
-
],
|
|
168
|
-
uninstall: [
|
|
169
|
-
`ALTER TABLE ${schema}.version DROP COLUMN maintained_on`
|
|
170
|
-
]
|
|
171
|
-
}
|
|
172
67
|
]
|
|
173
68
|
}
|