pg-boss 9.0.3 → 10.0.0-beta10
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 +19 -40
- package/package.json +7 -11
- package/src/attorney.js +81 -105
- package/src/boss.js +88 -139
- package/src/contractor.js +25 -4
- package/src/db.js +14 -8
- package/src/index.js +128 -93
- package/src/manager.js +222 -142
- package/src/migrationStore.js +0 -105
- package/src/plans.js +437 -361
- package/src/timekeeper.js +45 -82
- package/src/tools.js +28 -0
- package/src/worker.js +4 -4
- package/types.d.ts +76 -70
- 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_POLICIES } = 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,21 +172,21 @@ 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 {
|
|
183
|
-
|
|
180
|
+
pollingInterval: interval = this.config.pollingInterval,
|
|
184
181
|
batchSize,
|
|
185
182
|
teamSize = 1,
|
|
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) {
|
|
@@ -220,20 +217,20 @@ class Manager extends EventEmitter {
|
|
|
220
217
|
this.emitWip(name)
|
|
221
218
|
|
|
222
219
|
if (batchSize) {
|
|
223
|
-
const maxExpiration = jobs.reduce((acc, i) => Math.max(acc, i.
|
|
220
|
+
const maxExpiration = jobs.reduce((acc, i) => Math.max(acc, i.expireInSeconds), 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
|
|
231
228
|
}
|
|
232
229
|
|
|
233
230
|
const allTeamPromise = pMap(jobs, job =>
|
|
234
|
-
resolveWithinSeconds(callback(job), job.
|
|
235
|
-
.then(result => this.complete(job.id, result))
|
|
236
|
-
.catch(err => this.fail(job.id, err))
|
|
231
|
+
resolveWithinSeconds(callback(job), job.expireInSeconds)
|
|
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
|
|
@@ -320,21 +317,9 @@ class Manager extends EventEmitter {
|
|
|
320
317
|
async publish (event, ...args) {
|
|
321
318
|
assert(event, 'Missing required argument')
|
|
322
319
|
|
|
323
|
-
const
|
|
324
|
-
|
|
325
|
-
if (!result || result.rowCount === 0) {
|
|
326
|
-
return []
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
return await Promise.all(result.rows.map(({ name }) => this.send(name, ...args)))
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
async offComplete (value) {
|
|
333
|
-
if (typeof value === 'string') {
|
|
334
|
-
value = COMPLETION_JOB_PREFIX + value
|
|
335
|
-
}
|
|
320
|
+
const { rows } = await this.db.executeSql(this.getQueuesForEventCommand, [event])
|
|
336
321
|
|
|
337
|
-
return await this.
|
|
322
|
+
return await Promise.all(rows.map(({ name }) => this.send(name, ...args)))
|
|
338
323
|
}
|
|
339
324
|
|
|
340
325
|
async send (...args) {
|
|
@@ -342,26 +327,6 @@ class Manager extends EventEmitter {
|
|
|
342
327
|
return await this.createJob(name, data, options)
|
|
343
328
|
}
|
|
344
329
|
|
|
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
330
|
async sendAfter (name, data, options, after) {
|
|
366
331
|
options = options ? { ...options } : {}
|
|
367
332
|
options.startAfter = after
|
|
@@ -395,42 +360,52 @@ class Manager extends EventEmitter {
|
|
|
395
360
|
|
|
396
361
|
async createJob (name, data, options, singletonOffset = 0) {
|
|
397
362
|
const {
|
|
363
|
+
id = null,
|
|
398
364
|
db: wrapper,
|
|
399
|
-
expireIn,
|
|
400
365
|
priority,
|
|
401
366
|
startAfter,
|
|
402
|
-
keepUntil,
|
|
403
367
|
singletonKey = null,
|
|
404
368
|
singletonSeconds,
|
|
405
|
-
|
|
369
|
+
deadLetter = null,
|
|
370
|
+
expireIn,
|
|
371
|
+
expireInDefault,
|
|
372
|
+
keepUntil,
|
|
373
|
+
keepUntilDefault,
|
|
406
374
|
retryLimit,
|
|
375
|
+
retryLimitDefault,
|
|
407
376
|
retryDelay,
|
|
408
|
-
|
|
377
|
+
retryDelayDefault,
|
|
378
|
+
retryBackoff,
|
|
379
|
+
retryBackoffDefault
|
|
409
380
|
} = options
|
|
410
381
|
|
|
411
|
-
const id = uuid[this.config.uuid]()
|
|
412
|
-
|
|
413
382
|
const values = [
|
|
414
383
|
id, // 1
|
|
415
384
|
name, // 2
|
|
416
|
-
|
|
417
|
-
|
|
385
|
+
data, // 3
|
|
386
|
+
priority, // 4
|
|
418
387
|
startAfter, // 5
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
388
|
+
singletonKey, // 6
|
|
389
|
+
singletonSeconds, // 7
|
|
390
|
+
singletonOffset, // 8
|
|
391
|
+
deadLetter, // 9
|
|
392
|
+
expireIn, // 10
|
|
393
|
+
expireInDefault, // 11
|
|
394
|
+
keepUntil, // 12
|
|
395
|
+
keepUntilDefault, // 13
|
|
396
|
+
retryLimit, // 14
|
|
397
|
+
retryLimitDefault, // 15
|
|
398
|
+
retryDelay, // 16
|
|
399
|
+
retryDelayDefault, // 17
|
|
400
|
+
retryBackoff, // 18
|
|
401
|
+
retryBackoffDefault // 19
|
|
428
402
|
]
|
|
403
|
+
|
|
429
404
|
const db = wrapper || this.db
|
|
430
|
-
const
|
|
405
|
+
const { rows } = await db.executeSql(this.insertJobCommand, values)
|
|
431
406
|
|
|
432
|
-
if (
|
|
433
|
-
return
|
|
407
|
+
if (rows.length === 1) {
|
|
408
|
+
return rows[0].id
|
|
434
409
|
}
|
|
435
410
|
|
|
436
411
|
if (!options.singletonNextSlot) {
|
|
@@ -449,11 +424,20 @@ class Manager extends EventEmitter {
|
|
|
449
424
|
}
|
|
450
425
|
|
|
451
426
|
async insert (jobs, options = {}) {
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
const
|
|
455
|
-
|
|
456
|
-
|
|
427
|
+
assert(Array.isArray(jobs), 'jobs argument should be an array')
|
|
428
|
+
|
|
429
|
+
const db = options.db || this.db
|
|
430
|
+
|
|
431
|
+
const params = [
|
|
432
|
+
JSON.stringify(jobs), // 1
|
|
433
|
+
this.config.expireIn, // 2
|
|
434
|
+
this.config.keepUntil, // 3
|
|
435
|
+
this.config.retryLimit, // 4
|
|
436
|
+
this.config.retryDelay, // 5
|
|
437
|
+
this.config.retryBackoff // 6
|
|
438
|
+
]
|
|
439
|
+
|
|
440
|
+
return await db.executeSql(this.insertJobsCommand, params)
|
|
457
441
|
}
|
|
458
442
|
|
|
459
443
|
getDebounceStartAfter (singletonSeconds, clockOffset) {
|
|
@@ -476,25 +460,15 @@ class Manager extends EventEmitter {
|
|
|
476
460
|
async fetch (name, batchSize, options = {}) {
|
|
477
461
|
const values = Attorney.checkFetchArgs(name, batchSize, options)
|
|
478
462
|
const db = options.db || this.db
|
|
479
|
-
const
|
|
463
|
+
const nextJobSql = this.nextJobCommand({ ...options })
|
|
480
464
|
const statementValues = [values.name, batchSize || 1]
|
|
481
465
|
|
|
482
466
|
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)
|
|
467
|
+
|
|
468
|
+
try {
|
|
469
|
+
result = await db.executeSql(nextJobSql, statementValues)
|
|
470
|
+
} catch (err) {
|
|
471
|
+
// errors from fetchquery should only be unique constraint violations
|
|
498
472
|
}
|
|
499
473
|
|
|
500
474
|
if (!result || result.rows.length === 0) {
|
|
@@ -504,10 +478,6 @@ class Manager extends EventEmitter {
|
|
|
504
478
|
return result.rows.length === 1 && !batchSize ? result.rows[0] : result.rows
|
|
505
479
|
}
|
|
506
480
|
|
|
507
|
-
async fetchCompleted (name, batchSize, options = {}) {
|
|
508
|
-
return await this.fetch(COMPLETION_JOB_PREFIX + name, batchSize, options)
|
|
509
|
-
}
|
|
510
|
-
|
|
511
481
|
mapCompletionIdArg (id, funcName) {
|
|
512
482
|
const errorMessage = `${funcName}() requires an id`
|
|
513
483
|
|
|
@@ -538,45 +508,155 @@ class Manager extends EventEmitter {
|
|
|
538
508
|
}
|
|
539
509
|
}
|
|
540
510
|
|
|
541
|
-
async complete (id, data, options = {}) {
|
|
511
|
+
async complete (name, id, data, options = {}) {
|
|
512
|
+
assert(name, 'Missing queue name argument')
|
|
542
513
|
const db = options.db || this.db
|
|
543
514
|
const ids = this.mapCompletionIdArg(id, 'complete')
|
|
544
|
-
const result = await db.executeSql(this.completeJobsCommand, [ids, this.mapCompletionDataArg(data)])
|
|
515
|
+
const result = await db.executeSql(this.completeJobsCommand, [name, ids, this.mapCompletionDataArg(data)])
|
|
545
516
|
return this.mapCompletionResponse(ids, result)
|
|
546
517
|
}
|
|
547
518
|
|
|
548
|
-
async fail (id, data, options = {}) {
|
|
519
|
+
async fail (name, id, data, options = {}) {
|
|
520
|
+
assert(name, 'Missing queue name argument')
|
|
549
521
|
const db = options.db || this.db
|
|
550
522
|
const ids = this.mapCompletionIdArg(id, 'fail')
|
|
551
|
-
const result = await db.executeSql(this.
|
|
523
|
+
const result = await db.executeSql(this.failJobsByIdCommand, [name, ids, this.mapCompletionDataArg(data)])
|
|
552
524
|
return this.mapCompletionResponse(ids, result)
|
|
553
525
|
}
|
|
554
526
|
|
|
555
|
-
async cancel (id, options = {}) {
|
|
527
|
+
async cancel (name, id, options = {}) {
|
|
528
|
+
assert(name, 'Missing queue name argument')
|
|
556
529
|
const db = options.db || this.db
|
|
557
530
|
const ids = this.mapCompletionIdArg(id, 'cancel')
|
|
558
|
-
const result = await db.executeSql(this.cancelJobsCommand, [ids])
|
|
531
|
+
const result = await db.executeSql(this.cancelJobsCommand, [name, ids])
|
|
559
532
|
return this.mapCompletionResponse(ids, result)
|
|
560
533
|
}
|
|
561
534
|
|
|
562
|
-
async resume (id, options = {}) {
|
|
535
|
+
async resume (name, id, options = {}) {
|
|
536
|
+
assert(name, 'Missing queue name argument')
|
|
563
537
|
const db = options.db || this.db
|
|
564
538
|
const ids = this.mapCompletionIdArg(id, 'resume')
|
|
565
|
-
const result = await db.executeSql(this.resumeJobsCommand, [ids])
|
|
539
|
+
const result = await db.executeSql(this.resumeJobsCommand, [name, ids])
|
|
566
540
|
return this.mapCompletionResponse(ids, result)
|
|
567
541
|
}
|
|
568
542
|
|
|
569
|
-
async
|
|
570
|
-
assert(
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
543
|
+
async createQueue (name, options = {}) {
|
|
544
|
+
assert(name, 'Missing queue name argument')
|
|
545
|
+
|
|
546
|
+
Attorney.assertQueueName(name)
|
|
547
|
+
|
|
548
|
+
const { policy = QUEUE_POLICIES.standard } = options
|
|
549
|
+
|
|
550
|
+
assert(policy in QUEUE_POLICIES, `${policy} is not a valid queue policy`)
|
|
551
|
+
|
|
552
|
+
const {
|
|
553
|
+
retryLimit,
|
|
554
|
+
retryDelay,
|
|
555
|
+
retryBackoff,
|
|
556
|
+
expireInSeconds,
|
|
557
|
+
retentionMinutes,
|
|
558
|
+
deadLetter
|
|
559
|
+
} = Attorney.checkQueueArgs(name, options)
|
|
560
|
+
|
|
561
|
+
const paritionSql = plans.createPartition(this.config.schema, name)
|
|
562
|
+
|
|
563
|
+
await this.db.executeSql(paritionSql)
|
|
564
|
+
|
|
565
|
+
const sql = plans.createQueue(this.config.schema, name)
|
|
566
|
+
|
|
567
|
+
const params = [
|
|
568
|
+
name,
|
|
569
|
+
policy,
|
|
570
|
+
retryLimit,
|
|
571
|
+
retryDelay,
|
|
572
|
+
retryBackoff,
|
|
573
|
+
expireInSeconds,
|
|
574
|
+
retentionMinutes,
|
|
575
|
+
deadLetter
|
|
576
|
+
]
|
|
577
|
+
|
|
578
|
+
await this.db.executeSql(sql, params)
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
async updateQueue (name, options = {}) {
|
|
582
|
+
assert(name, 'Missing queue name argument')
|
|
583
|
+
|
|
584
|
+
const {
|
|
585
|
+
retryLimit,
|
|
586
|
+
retryDelay,
|
|
587
|
+
retryBackoff,
|
|
588
|
+
expireInSeconds,
|
|
589
|
+
retentionMinutes,
|
|
590
|
+
deadLetter
|
|
591
|
+
} = Attorney.checkQueueArgs(name, options)
|
|
592
|
+
|
|
593
|
+
const sql = plans.updateQueue(this.config.schema)
|
|
594
|
+
|
|
595
|
+
const params = [
|
|
596
|
+
name,
|
|
597
|
+
retryLimit,
|
|
598
|
+
retryDelay,
|
|
599
|
+
retryBackoff,
|
|
600
|
+
expireInSeconds,
|
|
601
|
+
retentionMinutes,
|
|
602
|
+
deadLetter
|
|
603
|
+
]
|
|
604
|
+
|
|
605
|
+
await this.db.executeSql(sql, params)
|
|
574
606
|
}
|
|
575
607
|
|
|
576
|
-
async
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
608
|
+
async getQueue (name) {
|
|
609
|
+
assert(name, 'Missing queue name argument')
|
|
610
|
+
|
|
611
|
+
const sql = plans.getQueueByName(this.config.schema)
|
|
612
|
+
const result = await this.db.executeSql(sql, [name])
|
|
613
|
+
|
|
614
|
+
if (result.rows.length === 0) {
|
|
615
|
+
return null
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
const {
|
|
619
|
+
policy,
|
|
620
|
+
retry_limit: retryLimit,
|
|
621
|
+
retry_delay: retryDelay,
|
|
622
|
+
retry_backoff: retryBackoff,
|
|
623
|
+
expire_seconds: expireInSeconds,
|
|
624
|
+
retention_minutes: retentionMinutes,
|
|
625
|
+
dead_letter: deadLetter
|
|
626
|
+
} = result.rows[0]
|
|
627
|
+
|
|
628
|
+
return {
|
|
629
|
+
name,
|
|
630
|
+
policy,
|
|
631
|
+
retryLimit,
|
|
632
|
+
retryDelay,
|
|
633
|
+
retryBackoff,
|
|
634
|
+
expireInSeconds,
|
|
635
|
+
retentionMinutes,
|
|
636
|
+
deadLetter
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
async deleteQueue (name) {
|
|
641
|
+
assert(name, 'Missing queue name argument')
|
|
642
|
+
|
|
643
|
+
const queueSql = plans.getQueueByName(this.config.schema)
|
|
644
|
+
const { rows } = await this.db.executeSql(queueSql, [name])
|
|
645
|
+
|
|
646
|
+
if (rows.length) {
|
|
647
|
+
Attorney.assertQueueName(name)
|
|
648
|
+
const sql = plans.dropPartition(this.config.schema, name)
|
|
649
|
+
await this.db.executeSql(sql)
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
const sql = plans.deleteQueueRecords(this.config.schema)
|
|
653
|
+
await this.db.executeSql(sql, [name])
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
async purgeQueue (queue) {
|
|
657
|
+
assert(queue, 'Missing queue name argument')
|
|
658
|
+
const sql = plans.purgeQueue(this.config.schema)
|
|
659
|
+
await this.db.executeSql(sql, [queue])
|
|
580
660
|
}
|
|
581
661
|
|
|
582
662
|
async clearStorage () {
|
|
@@ -594,15 +674,15 @@ class Manager extends EventEmitter {
|
|
|
594
674
|
return result ? parseFloat(result.rows[0].count) : null
|
|
595
675
|
}
|
|
596
676
|
|
|
597
|
-
async getJobById (id, options = {}) {
|
|
677
|
+
async getJobById (queue, id, options = {}) {
|
|
598
678
|
const db = options.db || this.db
|
|
599
|
-
const result1 = await db.executeSql(this.getJobByIdCommand, [id])
|
|
679
|
+
const result1 = await db.executeSql(this.getJobByIdCommand, [queue, id])
|
|
600
680
|
|
|
601
681
|
if (result1 && result1.rows && result1.rows.length === 1) {
|
|
602
682
|
return result1.rows[0]
|
|
603
683
|
}
|
|
604
684
|
|
|
605
|
-
const result2 = await db.executeSql(this.getArchivedJobByIdCommand, [id])
|
|
685
|
+
const result2 = await db.executeSql(this.getArchivedJobByIdCommand, [queue, id])
|
|
606
686
|
|
|
607
687
|
if (result2 && result2.rows && result2.rows.length === 1) {
|
|
608
688
|
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
|
}
|