pg-boss 10.0.0-beta16 → 10.0.0-beta18
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 +2 -2
- package/package.json +1 -2
- package/src/attorney.js +7 -8
- package/src/manager.js +53 -117
- package/src/plans.js +124 -77
- package/src/timekeeper.js +15 -24
- package/types.d.ts +16 -38
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ async function readme() {
|
|
|
19
19
|
|
|
20
20
|
console.log(`created job ${id} in queue ${queue}`)
|
|
21
21
|
|
|
22
|
-
await boss.work(queue, async job => {
|
|
22
|
+
await boss.work(queue, async ([ job ]) => {
|
|
23
23
|
console.log(`received job ${job.id} with data ${JSON.stringify(job.data)}`)
|
|
24
24
|
})
|
|
25
25
|
}
|
|
@@ -47,7 +47,7 @@ This will likely cater the most to teams already familiar with the simplicity of
|
|
|
47
47
|
|
|
48
48
|
## Installation
|
|
49
49
|
|
|
50
|
-
```
|
|
50
|
+
```bash
|
|
51
51
|
# npm
|
|
52
52
|
npm install pg-boss
|
|
53
53
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pg-boss",
|
|
3
|
-
"version": "10.0.0-
|
|
3
|
+
"version": "10.0.0-beta18",
|
|
4
4
|
"description": "Queueing jobs in Postgres from Node.js like a boss",
|
|
5
5
|
"main": "./src/index.js",
|
|
6
6
|
"engines": {
|
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
},
|
|
9
9
|
"dependencies": {
|
|
10
10
|
"cron-parser": "^4.0.0",
|
|
11
|
-
"p-map": "^4.0.0",
|
|
12
11
|
"pg": "^8.5.1",
|
|
13
12
|
"serialize-error": "^8.1.0"
|
|
14
13
|
},
|
package/src/attorney.js
CHANGED
|
@@ -124,24 +124,23 @@ function checkWorkArgs (name, args, defaults) {
|
|
|
124
124
|
|
|
125
125
|
applyPollingInterval(options, defaults)
|
|
126
126
|
|
|
127
|
-
assert(!('teamConcurrency' in options) ||
|
|
128
|
-
(Number.isInteger(options.teamConcurrency) && options.teamConcurrency >= 1 && options.teamConcurrency <= 1000),
|
|
129
|
-
'teamConcurrency must be an integer between 1 and 1000')
|
|
130
|
-
|
|
131
|
-
assert(!('teamSize' in options) || (Number.isInteger(options.teamSize) && options.teamSize >= 1), 'teamSize must be an integer > 0')
|
|
132
127
|
assert(!('batchSize' in options) || (Number.isInteger(options.batchSize) && options.batchSize >= 1), 'batchSize must be an integer > 0')
|
|
133
128
|
assert(!('includeMetadata' in options) || typeof options.includeMetadata === 'boolean', 'includeMetadata must be a boolean')
|
|
129
|
+
assert(!('priority' in options) || typeof options.priority === 'boolean', 'priority must be a boolean')
|
|
130
|
+
|
|
131
|
+
options.batchSize = options.batchSize || 1
|
|
134
132
|
|
|
135
133
|
return { options, callback }
|
|
136
134
|
}
|
|
137
135
|
|
|
138
|
-
function checkFetchArgs (name,
|
|
136
|
+
function checkFetchArgs (name, options) {
|
|
139
137
|
assert(name, 'missing queue name')
|
|
140
138
|
|
|
141
|
-
assert(!batchSize || (Number.isInteger(batchSize) && batchSize >= 1), 'batchSize must be an integer > 0')
|
|
139
|
+
assert(!('batchSize' in options) || (Number.isInteger(options.batchSize) && options.batchSize >= 1), 'batchSize must be an integer > 0')
|
|
142
140
|
assert(!('includeMetadata' in options) || typeof options.includeMetadata === 'boolean', 'includeMetadata must be a boolean')
|
|
141
|
+
assert(!('priority' in options) || typeof options.priority === 'boolean', 'priority must be a boolean')
|
|
143
142
|
|
|
144
|
-
|
|
143
|
+
options.batchSize = options.batchSize || 1
|
|
145
144
|
}
|
|
146
145
|
|
|
147
146
|
function getConfig (value) {
|
package/src/manager.js
CHANGED
|
@@ -2,7 +2,6 @@ const assert = require('assert')
|
|
|
2
2
|
const EventEmitter = require('events')
|
|
3
3
|
const { randomUUID } = require('crypto')
|
|
4
4
|
const { serializeError: stringify } = require('serialize-error')
|
|
5
|
-
const pMap = require('p-map')
|
|
6
5
|
const { delay } = require('./tools')
|
|
7
6
|
const Attorney = require('./attorney')
|
|
8
7
|
const Worker = require('./worker')
|
|
@@ -50,27 +49,27 @@ class Manager extends EventEmitter {
|
|
|
50
49
|
this.completeJobsCommand = plans.completeJobs(config.schema)
|
|
51
50
|
this.cancelJobsCommand = plans.cancelJobs(config.schema)
|
|
52
51
|
this.resumeJobsCommand = plans.resumeJobs(config.schema)
|
|
52
|
+
this.deleteJobsCommand = plans.deleteJobs(config.schema)
|
|
53
53
|
this.failJobsByIdCommand = plans.failJobsById(config.schema)
|
|
54
54
|
this.getJobByIdCommand = plans.getJobById(config.schema)
|
|
55
55
|
this.getArchivedJobByIdCommand = plans.getArchivedJobById(config.schema)
|
|
56
56
|
this.subscribeCommand = plans.subscribe(config.schema)
|
|
57
57
|
this.unsubscribeCommand = plans.unsubscribe(config.schema)
|
|
58
58
|
this.getQueuesCommand = plans.getQueues(config.schema)
|
|
59
|
-
this.getQueuesForEventCommand = plans.getQueuesForEvent(config.schema)
|
|
60
59
|
this.getQueueByNameCommand = plans.getQueueByName(config.schema)
|
|
61
|
-
this.
|
|
62
|
-
this.
|
|
60
|
+
this.getQueuesForEventCommand = plans.getQueuesForEvent(config.schema)
|
|
61
|
+
this.createQueueCommand = plans.createQueue(config.schema)
|
|
63
62
|
this.updateQueueCommand = plans.updateQueue(config.schema)
|
|
64
|
-
this.createPartitionCommand = plans.createPartition(config.schema)
|
|
65
|
-
this.dropPartitionCommand = plans.dropPartition(config.schema)
|
|
66
|
-
this.clearStorageCommand = plans.clearStorage(config.schema)
|
|
67
63
|
this.purgeQueueCommand = plans.purgeQueue(config.schema)
|
|
64
|
+
this.deleteQueueCommand = plans.deleteQueue(config.schema)
|
|
65
|
+
this.clearStorageCommand = plans.clearStorage(config.schema)
|
|
68
66
|
|
|
69
67
|
// exported api to index
|
|
70
68
|
this.functions = [
|
|
71
69
|
this.complete,
|
|
72
70
|
this.cancel,
|
|
73
71
|
this.resume,
|
|
72
|
+
this.delete,
|
|
74
73
|
this.fail,
|
|
75
74
|
this.fetch,
|
|
76
75
|
this.work,
|
|
@@ -189,71 +188,33 @@ class Manager extends EventEmitter {
|
|
|
189
188
|
const {
|
|
190
189
|
pollingInterval: interval = this.config.pollingInterval,
|
|
191
190
|
batchSize,
|
|
192
|
-
teamSize = 1,
|
|
193
|
-
teamConcurrency = 1,
|
|
194
|
-
teamRefill: refill = false,
|
|
195
191
|
includeMetadata = false,
|
|
196
192
|
priority = true
|
|
197
193
|
} = options
|
|
198
194
|
|
|
199
195
|
const id = randomUUID({ disableEntropyCache: true })
|
|
200
196
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
let refillTeamPromise
|
|
204
|
-
let resolveRefillTeam
|
|
205
|
-
|
|
206
|
-
// Setup a promise that onFetch can await for when at least one
|
|
207
|
-
// job is finished and so the team is ready to be topped up
|
|
208
|
-
const createTeamRefillPromise = () => {
|
|
209
|
-
refillTeamPromise = new Promise((resolve) => { resolveRefillTeam = resolve })
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
createTeamRefillPromise()
|
|
213
|
-
|
|
214
|
-
const onRefill = () => {
|
|
215
|
-
queueSize--
|
|
216
|
-
resolveRefillTeam()
|
|
217
|
-
createTeamRefillPromise()
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
const fetch = () => this.fetch(name, batchSize || (teamSize - queueSize), { includeMetadata, priority })
|
|
197
|
+
const fetch = () => this.fetch(name, { batchSize, includeMetadata, priority })
|
|
221
198
|
|
|
222
199
|
const onFetch = async (jobs) => {
|
|
200
|
+
if (!jobs.length) {
|
|
201
|
+
return
|
|
202
|
+
}
|
|
203
|
+
|
|
223
204
|
if (this.config.__test__throw_worker) {
|
|
224
205
|
throw new Error('__test__throw_worker')
|
|
225
206
|
}
|
|
226
207
|
|
|
227
208
|
this.emitWip(name)
|
|
228
209
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
queueSize += jobs.length || 1
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
const allTeamPromise = pMap(jobs, job =>
|
|
241
|
-
resolveWithinSeconds(callback(job), job.expireInSeconds)
|
|
242
|
-
.then(result => this.complete(name, job.id, result))
|
|
243
|
-
.catch(err => this.fail(name, job.id, err))
|
|
244
|
-
.then(() => refill ? onRefill() : null)
|
|
245
|
-
, { concurrency: teamConcurrency }
|
|
246
|
-
).catch(() => {}) // allow promises & non-promises to live together in harmony
|
|
247
|
-
|
|
248
|
-
if (refill) {
|
|
249
|
-
if (queueSize < teamSize) {
|
|
250
|
-
return
|
|
251
|
-
} else {
|
|
252
|
-
await refillTeamPromise
|
|
253
|
-
}
|
|
254
|
-
} else {
|
|
255
|
-
await allTeamPromise
|
|
256
|
-
}
|
|
210
|
+
const maxExpiration = jobs.reduce((acc, i) => Math.max(acc, i.expireInSeconds), 0)
|
|
211
|
+
const jobIds = jobs.map(job => job.id)
|
|
212
|
+
|
|
213
|
+
try {
|
|
214
|
+
const result = await resolveWithinSeconds(callback(jobs), maxExpiration)
|
|
215
|
+
this.complete(name, jobIds, jobIds.length === 1 ? result : undefined)
|
|
216
|
+
} catch (err) {
|
|
217
|
+
this.fail(name, jobIds, err)
|
|
257
218
|
}
|
|
258
219
|
|
|
259
220
|
this.emitWip(name)
|
|
@@ -329,7 +290,7 @@ class Manager extends EventEmitter {
|
|
|
329
290
|
|
|
330
291
|
const { rows } = await this.db.executeSql(this.getQueuesForEventCommand, [event])
|
|
331
292
|
|
|
332
|
-
|
|
293
|
+
await Promise.allSettled(rows.map(({ name }) => this.send(name, ...args)))
|
|
333
294
|
}
|
|
334
295
|
|
|
335
296
|
async send (...args) {
|
|
@@ -467,25 +428,20 @@ class Manager extends EventEmitter {
|
|
|
467
428
|
return startAfter
|
|
468
429
|
}
|
|
469
430
|
|
|
470
|
-
async fetch (name,
|
|
471
|
-
|
|
431
|
+
async fetch (name, options = {}) {
|
|
432
|
+
Attorney.checkFetchArgs(name, options)
|
|
472
433
|
const db = options.db || this.db
|
|
473
434
|
const nextJobSql = this.nextJobCommand({ ...options })
|
|
474
|
-
const statementValues = [values.name, batchSize || 1]
|
|
475
435
|
|
|
476
436
|
let result
|
|
477
437
|
|
|
478
438
|
try {
|
|
479
|
-
result = await db.executeSql(nextJobSql,
|
|
439
|
+
result = await db.executeSql(nextJobSql, [name, options.batchSize])
|
|
480
440
|
} catch (err) {
|
|
481
441
|
// errors from fetchquery should only be unique constraint violations
|
|
482
442
|
}
|
|
483
443
|
|
|
484
|
-
|
|
485
|
-
return null
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
return result.rows.length === 1 && !batchSize ? result.rows[0] : result.rows
|
|
444
|
+
return result?.rows || []
|
|
489
445
|
}
|
|
490
446
|
|
|
491
447
|
mapCompletionIdArg (id, funcName) {
|
|
@@ -510,11 +466,11 @@ class Manager extends EventEmitter {
|
|
|
510
466
|
return stringify(result)
|
|
511
467
|
}
|
|
512
468
|
|
|
513
|
-
|
|
469
|
+
mapCommandResponse (ids, result) {
|
|
514
470
|
return {
|
|
515
471
|
jobs: ids,
|
|
516
472
|
requested: ids.length,
|
|
517
|
-
|
|
473
|
+
affected: result && result.rows ? parseInt(result.rows[0].count) : 0
|
|
518
474
|
}
|
|
519
475
|
}
|
|
520
476
|
|
|
@@ -523,7 +479,7 @@ class Manager extends EventEmitter {
|
|
|
523
479
|
const db = options.db || this.db
|
|
524
480
|
const ids = this.mapCompletionIdArg(id, 'complete')
|
|
525
481
|
const result = await db.executeSql(this.completeJobsCommand, [name, ids, this.mapCompletionDataArg(data)])
|
|
526
|
-
return this.
|
|
482
|
+
return this.mapCommandResponse(ids, result)
|
|
527
483
|
}
|
|
528
484
|
|
|
529
485
|
async fail (name, id, data, options = {}) {
|
|
@@ -531,7 +487,7 @@ class Manager extends EventEmitter {
|
|
|
531
487
|
const db = options.db || this.db
|
|
532
488
|
const ids = this.mapCompletionIdArg(id, 'fail')
|
|
533
489
|
const result = await db.executeSql(this.failJobsByIdCommand, [name, ids, this.mapCompletionDataArg(data)])
|
|
534
|
-
return this.
|
|
490
|
+
return this.mapCommandResponse(ids, result)
|
|
535
491
|
}
|
|
536
492
|
|
|
537
493
|
async cancel (name, id, options = {}) {
|
|
@@ -539,7 +495,15 @@ class Manager extends EventEmitter {
|
|
|
539
495
|
const db = options.db || this.db
|
|
540
496
|
const ids = this.mapCompletionIdArg(id, 'cancel')
|
|
541
497
|
const result = await db.executeSql(this.cancelJobsCommand, [name, ids])
|
|
542
|
-
return this.
|
|
498
|
+
return this.mapCommandResponse(ids, result)
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
async delete (name, id, options = {}) {
|
|
502
|
+
Attorney.assertQueueName(name)
|
|
503
|
+
const db = options.db || this.db
|
|
504
|
+
const ids = this.mapCompletionIdArg(id, 'delete')
|
|
505
|
+
const result = await db.executeSql(this.deleteJobsCommand, [name, ids])
|
|
506
|
+
return this.mapCommandResponse(ids, result)
|
|
543
507
|
}
|
|
544
508
|
|
|
545
509
|
async resume (name, id, options = {}) {
|
|
@@ -547,7 +511,7 @@ class Manager extends EventEmitter {
|
|
|
547
511
|
const db = options.db || this.db
|
|
548
512
|
const ids = this.mapCompletionIdArg(id, 'resume')
|
|
549
513
|
const result = await db.executeSql(this.resumeJobsCommand, [name, ids])
|
|
550
|
-
return this.
|
|
514
|
+
return this.mapCommandResponse(ids, result)
|
|
551
515
|
}
|
|
552
516
|
|
|
553
517
|
async createQueue (name, options = {}) {
|
|
@@ -572,10 +536,8 @@ class Manager extends EventEmitter {
|
|
|
572
536
|
Attorney.assertQueueName(deadLetter)
|
|
573
537
|
}
|
|
574
538
|
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
const params = [
|
|
578
|
-
name,
|
|
539
|
+
// todo: pull in defaults from constructor config
|
|
540
|
+
const data = {
|
|
579
541
|
policy,
|
|
580
542
|
retryLimit,
|
|
581
543
|
retryDelay,
|
|
@@ -583,9 +545,9 @@ class Manager extends EventEmitter {
|
|
|
583
545
|
expireInSeconds,
|
|
584
546
|
retentionMinutes,
|
|
585
547
|
deadLetter
|
|
586
|
-
|
|
548
|
+
}
|
|
587
549
|
|
|
588
|
-
await this.db.executeSql(this.
|
|
550
|
+
await this.db.executeSql(this.createQueueCommand, [name, data])
|
|
589
551
|
}
|
|
590
552
|
|
|
591
553
|
async getQueues () {
|
|
@@ -626,32 +588,9 @@ class Manager extends EventEmitter {
|
|
|
626
588
|
async getQueue (name) {
|
|
627
589
|
Attorney.assertQueueName(name)
|
|
628
590
|
|
|
629
|
-
const
|
|
630
|
-
|
|
631
|
-
if (result.rows.length === 0) {
|
|
632
|
-
return null
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
const {
|
|
636
|
-
policy,
|
|
637
|
-
retry_limit: retryLimit,
|
|
638
|
-
retry_delay: retryDelay,
|
|
639
|
-
retry_backoff: retryBackoff,
|
|
640
|
-
expire_seconds: expireInSeconds,
|
|
641
|
-
retention_minutes: retentionMinutes,
|
|
642
|
-
dead_letter: deadLetter
|
|
643
|
-
} = result.rows[0]
|
|
591
|
+
const { rows } = await this.db.executeSql(this.getQueueByNameCommand, [name])
|
|
644
592
|
|
|
645
|
-
return
|
|
646
|
-
name,
|
|
647
|
-
policy,
|
|
648
|
-
retryLimit,
|
|
649
|
-
retryDelay,
|
|
650
|
-
retryBackoff,
|
|
651
|
-
expireInSeconds,
|
|
652
|
-
retentionMinutes,
|
|
653
|
-
deadLetter
|
|
654
|
-
}
|
|
593
|
+
return rows[0] || null
|
|
655
594
|
}
|
|
656
595
|
|
|
657
596
|
async deleteQueue (name) {
|
|
@@ -659,9 +598,8 @@ class Manager extends EventEmitter {
|
|
|
659
598
|
|
|
660
599
|
const { rows } = await this.db.executeSql(this.getQueueByNameCommand, [name])
|
|
661
600
|
|
|
662
|
-
if (rows.length) {
|
|
663
|
-
await this.db.executeSql(this.
|
|
664
|
-
await this.db.executeSql(this.deleteQueueRecordsCommand, [name])
|
|
601
|
+
if (rows.length === 1) {
|
|
602
|
+
await this.db.executeSql(this.deleteQueueCommand, [name])
|
|
665
603
|
}
|
|
666
604
|
}
|
|
667
605
|
|
|
@@ -688,19 +626,17 @@ class Manager extends EventEmitter {
|
|
|
688
626
|
Attorney.assertQueueName(name)
|
|
689
627
|
|
|
690
628
|
const db = options.db || this.db
|
|
629
|
+
|
|
691
630
|
const result1 = await db.executeSql(this.getJobByIdCommand, [name, id])
|
|
692
631
|
|
|
693
|
-
if (result1
|
|
632
|
+
if (result1?.rows?.length === 1) {
|
|
694
633
|
return result1.rows[0]
|
|
634
|
+
} else if (options.includeArchive) {
|
|
635
|
+
const result2 = await db.executeSql(this.getArchivedJobByIdCommand, [name, id])
|
|
636
|
+
return result2?.rows[0] || null
|
|
637
|
+
} else {
|
|
638
|
+
return null
|
|
695
639
|
}
|
|
696
|
-
|
|
697
|
-
const result2 = await db.executeSql(this.getArchivedJobByIdCommand, [name, id])
|
|
698
|
-
|
|
699
|
-
if (result2 && result2.rows && result2.rows.length === 1) {
|
|
700
|
-
return result2.rows[0]
|
|
701
|
-
}
|
|
702
|
-
|
|
703
|
-
return null
|
|
704
640
|
}
|
|
705
641
|
}
|
|
706
642
|
|
package/src/plans.js
CHANGED
|
@@ -28,6 +28,7 @@ module.exports = {
|
|
|
28
28
|
completeJobs,
|
|
29
29
|
cancelJobs,
|
|
30
30
|
resumeJobs,
|
|
31
|
+
deleteJobs,
|
|
31
32
|
failJobsById,
|
|
32
33
|
failJobsByTimeout,
|
|
33
34
|
insertJob,
|
|
@@ -42,11 +43,9 @@ module.exports = {
|
|
|
42
43
|
archive,
|
|
43
44
|
drop,
|
|
44
45
|
countStates,
|
|
45
|
-
insertQueue,
|
|
46
46
|
updateQueue,
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
deleteQueueRecords,
|
|
47
|
+
createQueue,
|
|
48
|
+
deleteQueue,
|
|
50
49
|
getQueues,
|
|
51
50
|
getQueueByName,
|
|
52
51
|
getQueueSize,
|
|
@@ -85,9 +84,8 @@ function create (schema, version) {
|
|
|
85
84
|
createColumnArchiveArchivedOn(schema),
|
|
86
85
|
createIndexArchiveArchivedOn(schema),
|
|
87
86
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
dropPartitionFunction(schema),
|
|
87
|
+
createQueueFunction(schema),
|
|
88
|
+
deleteQueueFunction(schema),
|
|
91
89
|
|
|
92
90
|
insertVersion(schema, version)
|
|
93
91
|
]
|
|
@@ -137,8 +135,10 @@ function createTableQueue (schema) {
|
|
|
137
135
|
retry_backoff bool,
|
|
138
136
|
expire_seconds int,
|
|
139
137
|
retention_minutes int,
|
|
140
|
-
dead_letter text,
|
|
138
|
+
dead_letter text REFERENCES ${schema}.queue (name),
|
|
139
|
+
partition_name text,
|
|
141
140
|
created_on timestamp with time zone not null default now(),
|
|
141
|
+
updated_on timestamp with time zone not null default now(),
|
|
142
142
|
PRIMARY KEY (name)
|
|
143
143
|
)
|
|
144
144
|
`
|
|
@@ -199,7 +199,10 @@ function createTableJob (schema) {
|
|
|
199
199
|
}
|
|
200
200
|
|
|
201
201
|
const baseJobColumns = 'id, name, data, EXTRACT(epoch FROM expire_in) as "expireInSeconds"'
|
|
202
|
-
const allJobColumns = `${baseJobColumns},
|
|
202
|
+
const allJobColumns = `${baseJobColumns},
|
|
203
|
+
policy,
|
|
204
|
+
state,
|
|
205
|
+
priority,
|
|
203
206
|
retry_limit as "retryLimit",
|
|
204
207
|
retry_count as "retryCount",
|
|
205
208
|
retry_delay as "retryDelay",
|
|
@@ -216,29 +219,38 @@ const allJobColumns = `${baseJobColumns}, policy, state, priority,
|
|
|
216
219
|
output
|
|
217
220
|
`
|
|
218
221
|
|
|
219
|
-
function
|
|
220
|
-
return `SELECT ${schema}.create_partition($1)`
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
function getPartitionFunction (schema) {
|
|
224
|
-
return `
|
|
225
|
-
CREATE FUNCTION ${schema}.get_partition(queue_name text, out name text) AS
|
|
226
|
-
$$
|
|
227
|
-
SELECT 'j' || lower(left(regexp_replace(queue_name, '\\W', '', 'g'),10)) || left(encode(sha224(queue_name::bytea), 'hex'),10);
|
|
228
|
-
$$
|
|
229
|
-
LANGUAGE SQL
|
|
230
|
-
IMMUTABLE
|
|
231
|
-
`
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
function createPartitionFunction (schema) {
|
|
222
|
+
function createQueueFunction (schema) {
|
|
235
223
|
return `
|
|
236
|
-
CREATE FUNCTION ${schema}.
|
|
224
|
+
CREATE FUNCTION ${schema}.create_queue(queue_name text, options json)
|
|
237
225
|
RETURNS VOID AS
|
|
238
226
|
$$
|
|
239
227
|
DECLARE
|
|
240
|
-
table_name varchar :=
|
|
228
|
+
table_name varchar := 'j' || encode(sha224(queue_name::bytea), 'hex');
|
|
241
229
|
BEGIN
|
|
230
|
+
|
|
231
|
+
INSERT INTO ${schema}.queue (
|
|
232
|
+
name,
|
|
233
|
+
policy,
|
|
234
|
+
retry_limit,
|
|
235
|
+
retry_delay,
|
|
236
|
+
retry_backoff,
|
|
237
|
+
expire_seconds,
|
|
238
|
+
retention_minutes,
|
|
239
|
+
dead_letter,
|
|
240
|
+
partition_name
|
|
241
|
+
)
|
|
242
|
+
VALUES (
|
|
243
|
+
queue_name,
|
|
244
|
+
options->>'policy',
|
|
245
|
+
(options->>'retryLimit')::int,
|
|
246
|
+
(options->>'retryDelay')::int,
|
|
247
|
+
(options->>'retryBackoff')::bool,
|
|
248
|
+
(options->>'expireInSeconds')::int,
|
|
249
|
+
(options->>'retentionMinutes')::int,
|
|
250
|
+
options->>'deadLetter',
|
|
251
|
+
table_name
|
|
252
|
+
);
|
|
253
|
+
|
|
242
254
|
EXECUTE format('CREATE TABLE ${schema}.%I (LIKE ${schema}.job INCLUDING DEFAULTS)', table_name);
|
|
243
255
|
|
|
244
256
|
EXECUTE format('${formatPartitionCommand(createPrimaryKeyJob(schema))}', table_name);
|
|
@@ -259,24 +271,37 @@ function createPartitionFunction (schema) {
|
|
|
259
271
|
}
|
|
260
272
|
|
|
261
273
|
function formatPartitionCommand (command) {
|
|
262
|
-
return command.replace('.job', '.%1$I').replace('
|
|
274
|
+
return command.replace('.job', '.%1$I').replace('job_i', '%1$s_i').replaceAll('\'', '\'\'')
|
|
263
275
|
}
|
|
264
276
|
|
|
265
|
-
function
|
|
277
|
+
function deleteQueueFunction (schema) {
|
|
266
278
|
return `
|
|
267
|
-
CREATE FUNCTION ${schema}.
|
|
279
|
+
CREATE FUNCTION ${schema}.delete_queue(queue_name text)
|
|
268
280
|
RETURNS VOID AS
|
|
269
281
|
$$
|
|
282
|
+
DECLARE
|
|
283
|
+
table_name varchar;
|
|
270
284
|
BEGIN
|
|
271
|
-
|
|
285
|
+
WITH deleted as (
|
|
286
|
+
DELETE FROM ${schema}.queue
|
|
287
|
+
WHERE name = queue_name
|
|
288
|
+
RETURNING partition_name
|
|
289
|
+
)
|
|
290
|
+
SELECT partition_name from deleted INTO table_name;
|
|
291
|
+
|
|
292
|
+
EXECUTE format('DROP TABLE IF EXISTS ${schema}.%I', table_name);
|
|
272
293
|
END;
|
|
273
294
|
$$
|
|
274
295
|
LANGUAGE plpgsql;
|
|
275
296
|
`
|
|
276
297
|
}
|
|
277
298
|
|
|
278
|
-
function
|
|
279
|
-
return `SELECT ${schema}.
|
|
299
|
+
function createQueue (schema) {
|
|
300
|
+
return `SELECT ${schema}.create_queue($1, $2)`
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
function deleteQueue (schema) {
|
|
304
|
+
return `SELECT ${schema}.delete_queue($1)`
|
|
280
305
|
}
|
|
281
306
|
|
|
282
307
|
function createPrimaryKeyJob (schema) {
|
|
@@ -284,11 +309,11 @@ function createPrimaryKeyJob (schema) {
|
|
|
284
309
|
}
|
|
285
310
|
|
|
286
311
|
function createQueueForeignKeyJob (schema) {
|
|
287
|
-
return `ALTER TABLE ${schema}.job ADD CONSTRAINT q_fkey FOREIGN KEY (name) REFERENCES ${schema}.queue (name) ON DELETE RESTRICT`
|
|
312
|
+
return `ALTER TABLE ${schema}.job ADD CONSTRAINT q_fkey FOREIGN KEY (name) REFERENCES ${schema}.queue (name) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED`
|
|
288
313
|
}
|
|
289
314
|
|
|
290
315
|
function createQueueForeignKeyJobDeadLetter (schema) {
|
|
291
|
-
return `ALTER TABLE ${schema}.job ADD CONSTRAINT dlq_fkey FOREIGN KEY (dead_letter) REFERENCES ${schema}.queue (name) ON DELETE RESTRICT`
|
|
316
|
+
return `ALTER TABLE ${schema}.job ADD CONSTRAINT dlq_fkey FOREIGN KEY (dead_letter) REFERENCES ${schema}.queue (name) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED`
|
|
292
317
|
}
|
|
293
318
|
|
|
294
319
|
function createPrimaryKeyArchive (schema) {
|
|
@@ -296,23 +321,23 @@ function createPrimaryKeyArchive (schema) {
|
|
|
296
321
|
}
|
|
297
322
|
|
|
298
323
|
function createIndexJobPolicyShort (schema) {
|
|
299
|
-
return `CREATE UNIQUE INDEX
|
|
324
|
+
return `CREATE UNIQUE INDEX job_i1 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state = '${JOB_STATES.created}' AND policy = '${QUEUE_POLICIES.short}';`
|
|
300
325
|
}
|
|
301
326
|
|
|
302
327
|
function createIndexJobPolicySingleton (schema) {
|
|
303
|
-
return `CREATE UNIQUE INDEX
|
|
328
|
+
return `CREATE UNIQUE INDEX job_i2 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state = '${JOB_STATES.active}' AND policy = '${QUEUE_POLICIES.singleton}'`
|
|
304
329
|
}
|
|
305
330
|
|
|
306
331
|
function createIndexJobPolicyStately (schema) {
|
|
307
|
-
return `CREATE UNIQUE INDEX
|
|
332
|
+
return `CREATE UNIQUE INDEX job_i3 ON ${schema}.job (name, state, COALESCE(singleton_key, '')) WHERE state <= '${JOB_STATES.active}' AND policy = '${QUEUE_POLICIES.stately}'`
|
|
308
333
|
}
|
|
309
334
|
|
|
310
335
|
function createIndexJobThrottle (schema) {
|
|
311
|
-
return `CREATE UNIQUE INDEX
|
|
336
|
+
return `CREATE UNIQUE INDEX job_i4 ON ${schema}.job (name, singleton_on, COALESCE(singleton_key, '')) WHERE state <> '${JOB_STATES.cancelled}' AND singleton_on IS NOT NULL`
|
|
312
337
|
}
|
|
313
338
|
|
|
314
339
|
function createIndexJobFetch (schema) {
|
|
315
|
-
return `CREATE INDEX
|
|
340
|
+
return `CREATE INDEX job_i5 ON ${schema}.job (name, start_after) INCLUDE (priority, created_on, id) WHERE state < '${JOB_STATES.active}'`
|
|
316
341
|
}
|
|
317
342
|
|
|
318
343
|
function createTableArchive (schema) {
|
|
@@ -324,7 +349,7 @@ function createColumnArchiveArchivedOn (schema) {
|
|
|
324
349
|
}
|
|
325
350
|
|
|
326
351
|
function createIndexArchiveArchivedOn (schema) {
|
|
327
|
-
return `CREATE INDEX
|
|
352
|
+
return `CREATE INDEX archive_i1 ON ${schema}.archive(archived_on)`
|
|
328
353
|
}
|
|
329
354
|
|
|
330
355
|
function trySetMaintenanceTime (schema) {
|
|
@@ -347,13 +372,6 @@ function trySetTimestamp (schema, column) {
|
|
|
347
372
|
`
|
|
348
373
|
}
|
|
349
374
|
|
|
350
|
-
function insertQueue (schema) {
|
|
351
|
-
return `
|
|
352
|
-
INSERT INTO ${schema}.queue (name, policy, retry_limit, retry_delay, retry_backoff, expire_seconds, retention_minutes, dead_letter)
|
|
353
|
-
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
|
354
|
-
`
|
|
355
|
-
}
|
|
356
|
-
|
|
357
375
|
function updateQueue (schema) {
|
|
358
376
|
return `
|
|
359
377
|
UPDATE ${schema}.queue SET
|
|
@@ -363,21 +381,28 @@ function updateQueue (schema) {
|
|
|
363
381
|
retry_backoff = COALESCE($5, retry_backoff),
|
|
364
382
|
expire_seconds = COALESCE($6, expire_seconds),
|
|
365
383
|
retention_minutes = COALESCE($7, retention_minutes),
|
|
366
|
-
dead_letter = COALESCE($8, dead_letter)
|
|
384
|
+
dead_letter = COALESCE($8, dead_letter),
|
|
385
|
+
updated_on = now()
|
|
367
386
|
WHERE name = $1
|
|
368
387
|
`
|
|
369
388
|
}
|
|
370
389
|
|
|
371
390
|
function getQueues (schema) {
|
|
372
|
-
return `
|
|
391
|
+
return `
|
|
392
|
+
SELECT
|
|
393
|
+
policy,
|
|
394
|
+
retry_limit as "retryLimit",
|
|
395
|
+
retry_delay as "retryDelay",
|
|
396
|
+
retry_backoff as "retryBackoff",
|
|
397
|
+
expire_seconds as "expireInSeconds",
|
|
398
|
+
retention_minutes as "retentionMinutes",
|
|
399
|
+
dead_letter as "deadLetter"
|
|
400
|
+
FROM ${schema}.queue
|
|
401
|
+
`
|
|
373
402
|
}
|
|
374
403
|
|
|
375
404
|
function getQueueByName (schema) {
|
|
376
|
-
return
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
function deleteQueueRecords (schema) {
|
|
380
|
-
return `DELETE FROM ${schema}.queue WHERE name = $1`
|
|
405
|
+
return `${getQueues(schema)} WHERE name = $1`
|
|
381
406
|
}
|
|
382
407
|
|
|
383
408
|
function purgeQueue (schema) {
|
|
@@ -577,6 +602,19 @@ function resumeJobs (schema) {
|
|
|
577
602
|
state = '${JOB_STATES.created}'
|
|
578
603
|
WHERE name = $1
|
|
579
604
|
AND id IN (SELECT UNNEST($2::uuid[]))
|
|
605
|
+
AND state = '${JOB_STATES.cancelled}'
|
|
606
|
+
RETURNING 1
|
|
607
|
+
)
|
|
608
|
+
SELECT COUNT(*) from results
|
|
609
|
+
`
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
function deleteJobs (schema) {
|
|
613
|
+
return `
|
|
614
|
+
with results as (
|
|
615
|
+
DELETE FROM ${schema}.job
|
|
616
|
+
WHERE name = $1
|
|
617
|
+
AND id IN (SELECT UNNEST($2::uuid[]))
|
|
580
618
|
RETURNING 1
|
|
581
619
|
)
|
|
582
620
|
SELECT COUNT(*) from results
|
|
@@ -654,7 +692,7 @@ function insertJob (schema) {
|
|
|
654
692
|
$17::int as retry_delay_default,
|
|
655
693
|
$18::bool as retry_backoff,
|
|
656
694
|
$19::bool as retry_backoff_default
|
|
657
|
-
) j
|
|
695
|
+
) j JOIN ${schema}.queue q ON j.name = q.name
|
|
658
696
|
ON CONFLICT DO NOTHING
|
|
659
697
|
RETURNING id
|
|
660
698
|
`
|
|
@@ -689,10 +727,10 @@ function insertJobs (schema) {
|
|
|
689
727
|
COALESCE(id, gen_random_uuid()) as id,
|
|
690
728
|
j.name,
|
|
691
729
|
data,
|
|
692
|
-
COALESCE(priority, 0),
|
|
693
|
-
|
|
694
|
-
"singletonKey",
|
|
695
|
-
COALESCE("deadLetter", q.dead_letter),
|
|
730
|
+
COALESCE(priority, 0) as priority,
|
|
731
|
+
j.start_after,
|
|
732
|
+
"singletonKey" as singleton_key,
|
|
733
|
+
COALESCE("deadLetter", q.dead_letter) as dead_letter,
|
|
696
734
|
CASE
|
|
697
735
|
WHEN "expireInSeconds" IS NOT NULL THEN "expireInSeconds" * interval '1s'
|
|
698
736
|
WHEN q.expire_seconds IS NOT NULL THEN q.expire_seconds * interval '1s'
|
|
@@ -701,7 +739,7 @@ function insertJobs (schema) {
|
|
|
701
739
|
END as expire_in,
|
|
702
740
|
CASE
|
|
703
741
|
WHEN "keepUntil" IS NOT NULL THEN "keepUntil"
|
|
704
|
-
ELSE COALESCE(
|
|
742
|
+
ELSE COALESCE(j.start_after, now()) + CAST(COALESCE((q.retention_minutes * 60)::text, defaults.keep_until, '14 days') as interval)
|
|
705
743
|
END as keep_until,
|
|
706
744
|
COALESCE("retryLimit", q.retry_limit, defaults.retry_limit, 2),
|
|
707
745
|
CASE
|
|
@@ -711,21 +749,29 @@ function insertJobs (schema) {
|
|
|
711
749
|
END as retry_delay,
|
|
712
750
|
COALESCE("retryBackoff", q.retry_backoff, defaults.retry_backoff, false) as retry_backoff,
|
|
713
751
|
q.policy
|
|
714
|
-
FROM
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
752
|
+
FROM (
|
|
753
|
+
SELECT *,
|
|
754
|
+
CASE
|
|
755
|
+
WHEN right("startAfter", 1) = 'Z' THEN CAST("startAfter" as timestamp with time zone)
|
|
756
|
+
ELSE now() + CAST(COALESCE("startAfter",'0') as interval)
|
|
757
|
+
END as start_after
|
|
758
|
+
FROM json_to_recordset($1) as x (
|
|
759
|
+
id uuid,
|
|
760
|
+
name text,
|
|
761
|
+
priority integer,
|
|
762
|
+
data jsonb,
|
|
763
|
+
"startAfter" text,
|
|
764
|
+
"retryLimit" integer,
|
|
765
|
+
"retryDelay" integer,
|
|
766
|
+
"retryBackoff" boolean,
|
|
767
|
+
"singletonKey" text,
|
|
768
|
+
"singletonOn" text,
|
|
769
|
+
"expireInSeconds" integer,
|
|
770
|
+
"keepUntil" timestamp with time zone,
|
|
771
|
+
"deadLetter" text
|
|
772
|
+
)
|
|
773
|
+
) j
|
|
774
|
+
JOIN ${schema}.queue q ON j.name = q.name,
|
|
729
775
|
defaults
|
|
730
776
|
ON CONFLICT DO NOTHING
|
|
731
777
|
`
|
|
@@ -752,6 +798,7 @@ function archive (schema, completedInterval, failedInterval = completedInterval)
|
|
|
752
798
|
INSERT INTO ${schema}.archive (${columns})
|
|
753
799
|
SELECT ${columns}
|
|
754
800
|
FROM archived_rows
|
|
801
|
+
ON CONFLICT DO NOTHING
|
|
755
802
|
`
|
|
756
803
|
}
|
|
757
804
|
|
|
@@ -779,7 +826,7 @@ function locked (schema, query) {
|
|
|
779
826
|
}
|
|
780
827
|
|
|
781
828
|
function advisoryLock (schema, key) {
|
|
782
|
-
return `SELECT pg_advisory_xact_lock(
|
|
829
|
+
return `SELECT pg_advisory_xact_lock(
|
|
783
830
|
('x' || encode(sha224((current_database() || '.pgboss.${schema}${key || ''}')::bytea), 'hex'))::bit(64)::bigint
|
|
784
831
|
)`
|
|
785
832
|
}
|
package/src/timekeeper.js
CHANGED
|
@@ -2,13 +2,12 @@ const EventEmitter = require('events')
|
|
|
2
2
|
const plans = require('./plans')
|
|
3
3
|
const cronParser = require('cron-parser')
|
|
4
4
|
const Attorney = require('./attorney')
|
|
5
|
-
const pMap = require('p-map')
|
|
6
5
|
|
|
7
|
-
const
|
|
6
|
+
const QUEUES = {
|
|
8
7
|
SEND_IT: '__pgboss__send-it'
|
|
9
8
|
}
|
|
10
9
|
|
|
11
|
-
const
|
|
10
|
+
const EVENTS = {
|
|
12
11
|
error: 'error',
|
|
13
12
|
schedule: 'schedule'
|
|
14
13
|
}
|
|
@@ -24,7 +23,7 @@ class Timekeeper extends EventEmitter {
|
|
|
24
23
|
this.cronMonitorIntervalMs = config.cronMonitorIntervalSeconds * 1000
|
|
25
24
|
this.clockSkew = 0
|
|
26
25
|
|
|
27
|
-
this.events =
|
|
26
|
+
this.events = EVENTS
|
|
28
27
|
|
|
29
28
|
this.getTimeCommand = plans.getTime(config.schema)
|
|
30
29
|
this.getQueueCommand = plans.getQueueByName(config.schema)
|
|
@@ -53,16 +52,15 @@ class Timekeeper extends EventEmitter {
|
|
|
53
52
|
await this.cacheClockSkew()
|
|
54
53
|
|
|
55
54
|
try {
|
|
56
|
-
await this.manager.createQueue(
|
|
55
|
+
await this.manager.createQueue(QUEUES.SEND_IT)
|
|
57
56
|
} catch {}
|
|
58
57
|
|
|
59
58
|
const options = {
|
|
60
59
|
pollingIntervalSeconds: this.config.cronWorkerIntervalSeconds,
|
|
61
|
-
|
|
62
|
-
teamConcurrency: 5
|
|
60
|
+
batchSize: 50
|
|
63
61
|
}
|
|
64
62
|
|
|
65
|
-
await this.manager.work(
|
|
63
|
+
await this.manager.work(QUEUES.SEND_IT, options, (jobs) => this.manager.insert(jobs.map(i => i.data)))
|
|
66
64
|
|
|
67
65
|
setImmediate(() => this.onCron())
|
|
68
66
|
|
|
@@ -77,7 +75,7 @@ class Timekeeper extends EventEmitter {
|
|
|
77
75
|
|
|
78
76
|
this.stopped = true
|
|
79
77
|
|
|
80
|
-
await this.manager.offWork(
|
|
78
|
+
await this.manager.offWork(QUEUES.SEND_IT)
|
|
81
79
|
|
|
82
80
|
if (this.skewMonitorInterval) {
|
|
83
81
|
clearInterval(this.skewMonitorInterval)
|
|
@@ -141,12 +139,15 @@ class Timekeeper extends EventEmitter {
|
|
|
141
139
|
}
|
|
142
140
|
|
|
143
141
|
async cron () {
|
|
144
|
-
const
|
|
142
|
+
const schedules = await this.getSchedules()
|
|
145
143
|
|
|
146
|
-
const
|
|
144
|
+
const scheduled = schedules
|
|
145
|
+
.filter(i => this.shouldSendIt(i.cron, i.timezone))
|
|
146
|
+
.map(({ name, data, options }) =>
|
|
147
|
+
({ name: QUEUES.SEND_IT, data: { name, data, options }, options: { singletonKey: name, singletonSeconds: 60 } }))
|
|
147
148
|
|
|
148
|
-
if (
|
|
149
|
-
await
|
|
149
|
+
if (scheduled.length > 0 && !this.stopped) {
|
|
150
|
+
await this.manager.insert(scheduled)
|
|
150
151
|
}
|
|
151
152
|
}
|
|
152
153
|
|
|
@@ -162,16 +163,6 @@ class Timekeeper extends EventEmitter {
|
|
|
162
163
|
return prevDiff < 60
|
|
163
164
|
}
|
|
164
165
|
|
|
165
|
-
async send (job) {
|
|
166
|
-
await this.manager.send(queues.SEND_IT, job, { singletonKey: job.name, singletonSeconds: 60 })
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
async onSendIt (job) {
|
|
170
|
-
if (this.stopped) return
|
|
171
|
-
const { name, data, options } = job.data
|
|
172
|
-
await this.manager.send(name, data, options)
|
|
173
|
-
}
|
|
174
|
-
|
|
175
166
|
async getSchedules () {
|
|
176
167
|
const { rows } = await this.db.executeSql(this.getSchedulesCommand)
|
|
177
168
|
return rows
|
|
@@ -203,4 +194,4 @@ class Timekeeper extends EventEmitter {
|
|
|
203
194
|
}
|
|
204
195
|
|
|
205
196
|
module.exports = Timekeeper
|
|
206
|
-
module.exports.QUEUES =
|
|
197
|
+
module.exports.QUEUES = QUEUES
|
package/types.d.ts
CHANGED
|
@@ -114,7 +114,7 @@ declare namespace PgBoss {
|
|
|
114
114
|
|
|
115
115
|
type QueuePolicy = 'standard' | 'short' | 'singleton' | 'stately'
|
|
116
116
|
|
|
117
|
-
type Queue = RetryOptions & ExpirationOptions & RetentionOptions & { name: string, policy
|
|
117
|
+
type Queue = RetryOptions & ExpirationOptions & RetentionOptions & { name: string, policy?: QueuePolicy, deadLetter?: string }
|
|
118
118
|
|
|
119
119
|
type ScheduleOptions = SendOptions & { tz?: string }
|
|
120
120
|
|
|
@@ -122,41 +122,20 @@ declare namespace PgBoss {
|
|
|
122
122
|
pollingIntervalSeconds?: number;
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
-
interface
|
|
125
|
+
interface JobFetchOptions {
|
|
126
126
|
includeMetadata?: boolean;
|
|
127
127
|
priority?: boolean;
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
type JobFetchOptions = CommonJobFetchOptions & {
|
|
131
|
-
teamSize?: number;
|
|
132
|
-
teamConcurrency?: number;
|
|
133
|
-
teamRefill?: boolean;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
type BatchJobFetchOptions = CommonJobFetchOptions & {
|
|
137
|
-
batchSize: number;
|
|
128
|
+
batchSize?: number;
|
|
138
129
|
}
|
|
139
130
|
|
|
140
131
|
type WorkOptions = JobFetchOptions & JobPollingOptions
|
|
141
|
-
type
|
|
142
|
-
|
|
143
|
-
type FetchOptions = {
|
|
144
|
-
includeMetadata?: boolean;
|
|
145
|
-
} & ConnectionOptions;
|
|
132
|
+
type FetchOptions = JobFetchOptions & ConnectionOptions;
|
|
146
133
|
|
|
147
134
|
interface WorkHandler<ReqData> {
|
|
148
|
-
(job: PgBoss.Job<ReqData>): Promise<any>;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
interface BatchWorkHandler<ReqData> {
|
|
152
135
|
(job: PgBoss.Job<ReqData>[]): Promise<any>;
|
|
153
136
|
}
|
|
154
137
|
|
|
155
138
|
interface WorkWithMetadataHandler<ReqData> {
|
|
156
|
-
(job: PgBoss.JobWithMetadata<ReqData>): Promise<any>;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
interface BatchWorkWithMetadataHandler<ReqData> {
|
|
160
139
|
(job: PgBoss.JobWithMetadata<ReqData>[]): Promise<any>;
|
|
161
140
|
}
|
|
162
141
|
|
|
@@ -328,13 +307,14 @@ declare class PgBoss extends EventEmitter {
|
|
|
328
307
|
insert(jobs: PgBoss.JobInsert[]): Promise<void>;
|
|
329
308
|
insert(jobs: PgBoss.JobInsert[], options: PgBoss.InsertOptions): Promise<void>;
|
|
330
309
|
|
|
310
|
+
fetch<T>(name: string): Promise<PgBoss.Job<T>[]>;
|
|
311
|
+
fetch<T>(name: string, options: PgBoss.FetchOptions & { includeMetadata: true }): Promise<PgBoss.JobWithMetadata<T>[]>;
|
|
312
|
+
fetch<T>(name: string, options: PgBoss.FetchOptions): Promise<PgBoss.Job<T>[]>;
|
|
313
|
+
|
|
331
314
|
work<ReqData>(name: string, handler: PgBoss.WorkHandler<ReqData>): Promise<string>;
|
|
332
315
|
work<ReqData>(name: string, options: PgBoss.WorkOptions & { includeMetadata: true }, handler: PgBoss.WorkWithMetadataHandler<ReqData>): Promise<string>;
|
|
333
316
|
work<ReqData>(name: string, options: PgBoss.WorkOptions, handler: PgBoss.WorkHandler<ReqData>): Promise<string>;
|
|
334
317
|
|
|
335
|
-
work<ReqData>(name: string, options: PgBoss.BatchWorkOptions & { includeMetadata: true }, handler: PgBoss.BatchWorkWithMetadataHandler<ReqData>): Promise<string>;
|
|
336
|
-
work<ReqData>(name: string, options: PgBoss.BatchWorkOptions, handler: PgBoss.BatchWorkHandler<ReqData>): Promise<string>;
|
|
337
|
-
|
|
338
318
|
offWork(name: string): Promise<void>;
|
|
339
319
|
offWork(options: PgBoss.OffWorkOptions): Promise<void>;
|
|
340
320
|
|
|
@@ -342,14 +322,9 @@ declare class PgBoss extends EventEmitter {
|
|
|
342
322
|
|
|
343
323
|
subscribe(event: string, name: string): Promise<void>;
|
|
344
324
|
unsubscribe(event: string, name: string): Promise<void>;
|
|
345
|
-
publish(event: string): Promise<
|
|
346
|
-
publish(event: string, data: object): Promise<
|
|
347
|
-
publish(event: string, data: object, options: PgBoss.SendOptions): Promise<
|
|
348
|
-
|
|
349
|
-
fetch<T>(name: string): Promise<PgBoss.Job<T> | null>;
|
|
350
|
-
fetch<T>(name: string, batchSize: number): Promise<PgBoss.Job<T>[] | null>;
|
|
351
|
-
fetch<T>(name: string, batchSize: number, options: PgBoss.FetchOptions & { includeMetadata: true }): Promise<PgBoss.JobWithMetadata<T>[] | null>;
|
|
352
|
-
fetch<T>(name: string, batchSize: number, options: PgBoss.FetchOptions): Promise<PgBoss.Job<T>[] | null>;
|
|
325
|
+
publish(event: string): Promise<void>;
|
|
326
|
+
publish(event: string, data: object): Promise<void>;
|
|
327
|
+
publish(event: string, data: object, options: PgBoss.SendOptions): Promise<void>;
|
|
353
328
|
|
|
354
329
|
cancel(name: string, id: string, options?: PgBoss.ConnectionOptions): Promise<void>;
|
|
355
330
|
cancel(name: string, ids: string[], options?: PgBoss.ConnectionOptions): Promise<void>;
|
|
@@ -357,6 +332,9 @@ declare class PgBoss extends EventEmitter {
|
|
|
357
332
|
resume(name: string, id: string, options?: PgBoss.ConnectionOptions): Promise<void>;
|
|
358
333
|
resume(name: string, ids: string[], options?: PgBoss.ConnectionOptions): Promise<void>;
|
|
359
334
|
|
|
335
|
+
delete(name: string, id: string, options?: PgBoss.ConnectionOptions): Promise<void>;
|
|
336
|
+
delete(name: string, ids: string[], options?: PgBoss.ConnectionOptions): Promise<void>;
|
|
337
|
+
|
|
360
338
|
complete(name: string, id: string, options?: PgBoss.ConnectionOptions): Promise<void>;
|
|
361
339
|
complete(name: string, id: string, data: object, options?: PgBoss.ConnectionOptions): Promise<void>;
|
|
362
340
|
complete(name: string, ids: string[], options?: PgBoss.ConnectionOptions): Promise<void>;
|
|
@@ -366,11 +344,11 @@ declare class PgBoss extends EventEmitter {
|
|
|
366
344
|
fail(name: string, ids: string[], options?: PgBoss.ConnectionOptions): Promise<void>;
|
|
367
345
|
|
|
368
346
|
getQueueSize(name: string, options?: object): Promise<number>;
|
|
369
|
-
getJobById(name: string, id: string, options?: PgBoss.ConnectionOptions): Promise<PgBoss.JobWithMetadata | null>;
|
|
347
|
+
getJobById(name: string, id: string, options?: PgBoss.ConnectionOptions & { includeArchive: bool }): Promise<PgBoss.JobWithMetadata | null>;
|
|
370
348
|
|
|
371
349
|
createQueue(name: string, options?: PgBoss.Queue): Promise<void>;
|
|
372
350
|
getQueue(name: string): Promise<PgBoss.Queue | null>;
|
|
373
|
-
getQueues(): Promise<
|
|
351
|
+
getQueues(): Promise<PgBoss.Queue[]>;
|
|
374
352
|
updateQueue(name: string, options?: PgBoss.Queue): Promise<void>;
|
|
375
353
|
deleteQueue(name: string): Promise<void>;
|
|
376
354
|
purgeQueue(name: string): Promise<void>;
|