pg-boss 10.1.6 → 10.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -1
- package/docker-compose.yaml +15 -0
- package/package.json +5 -5
- package/src/attorney.js +1 -0
- package/src/manager.js +10 -0
- package/src/plans.js +29 -13
- package/types.d.ts +3 -0
package/README.md
CHANGED
|
@@ -82,4 +82,10 @@ To run the test suite, linter and code coverage:
|
|
|
82
82
|
npm run cover
|
|
83
83
|
```
|
|
84
84
|
|
|
85
|
-
The test suite will try and create a new database named pgboss. The [config.json](test/config.json) file has the default credentials to connect to postgres.
|
|
85
|
+
The test suite will try and create a new database named pgboss. The [config.json](test/config.json) file has the default credentials to connect to postgres.
|
|
86
|
+
|
|
87
|
+
The [Docker Compose](docker-compose.yaml) file can be used to start a local postgres instance for testing:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
docker-compose up -d
|
|
91
|
+
```
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
services:
|
|
2
|
+
db:
|
|
3
|
+
image: postgres:16
|
|
4
|
+
ports:
|
|
5
|
+
- 5432:5432
|
|
6
|
+
volumes:
|
|
7
|
+
- db_volume:/var/lib/postgresql/data
|
|
8
|
+
environment:
|
|
9
|
+
- POSTGRES_DB=pgboss
|
|
10
|
+
- POSTGRES_NAME=pgboss
|
|
11
|
+
- POSTGRES_USER=postgres
|
|
12
|
+
- POSTGRES_PASSWORD=postgres
|
|
13
|
+
|
|
14
|
+
volumes:
|
|
15
|
+
db_volume:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pg-boss",
|
|
3
|
-
"version": "10.
|
|
3
|
+
"version": "10.3.0",
|
|
4
4
|
"description": "Queueing jobs in Postgres from Node.js like a boss",
|
|
5
5
|
"main": "./src/index.js",
|
|
6
6
|
"engines": {
|
|
@@ -8,13 +8,13 @@
|
|
|
8
8
|
},
|
|
9
9
|
"dependencies": {
|
|
10
10
|
"cron-parser": "^4.9.0",
|
|
11
|
-
"pg": "^8.
|
|
11
|
+
"pg": "^8.16.0",
|
|
12
12
|
"serialize-error": "^8.1.0"
|
|
13
13
|
},
|
|
14
14
|
"devDependencies": {
|
|
15
|
-
"@types/node": "^20.
|
|
16
|
-
"luxon": "^3.
|
|
17
|
-
"mocha": "^10.
|
|
15
|
+
"@types/node": "^20.17.57",
|
|
16
|
+
"luxon": "^3.6.1",
|
|
17
|
+
"mocha": "^10.8.2",
|
|
18
18
|
"nyc": "^17.1.0",
|
|
19
19
|
"standard": "^17.1.2"
|
|
20
20
|
},
|
package/src/attorney.js
CHANGED
|
@@ -143,6 +143,7 @@ function checkFetchArgs (name, options) {
|
|
|
143
143
|
assert(!('batchSize' in options) || (Number.isInteger(options.batchSize) && options.batchSize >= 1), 'batchSize must be an integer > 0')
|
|
144
144
|
assert(!('includeMetadata' in options) || typeof options.includeMetadata === 'boolean', 'includeMetadata must be a boolean')
|
|
145
145
|
assert(!('priority' in options) || typeof options.priority === 'boolean', 'priority must be a boolean')
|
|
146
|
+
assert(!('ignoreStartAfter' in options) || typeof options.ignoreStartAfter === 'boolean', 'ignoreStartAfter must be a boolean')
|
|
146
147
|
|
|
147
148
|
options.batchSize = options.batchSize || 1
|
|
148
149
|
}
|
package/src/manager.js
CHANGED
|
@@ -50,6 +50,7 @@ class Manager extends EventEmitter {
|
|
|
50
50
|
this.cancelJobsCommand = plans.cancelJobs(config.schema)
|
|
51
51
|
this.resumeJobsCommand = plans.resumeJobs(config.schema)
|
|
52
52
|
this.deleteJobsCommand = plans.deleteJobs(config.schema)
|
|
53
|
+
this.retryJobsCommand = plans.retryJobs(config.schema)
|
|
53
54
|
this.failJobsByIdCommand = plans.failJobsById(config.schema)
|
|
54
55
|
this.getJobByIdCommand = plans.getJobById(config.schema)
|
|
55
56
|
this.getArchivedJobByIdCommand = plans.getArchivedJobById(config.schema)
|
|
@@ -69,6 +70,7 @@ class Manager extends EventEmitter {
|
|
|
69
70
|
this.complete,
|
|
70
71
|
this.cancel,
|
|
71
72
|
this.resume,
|
|
73
|
+
this.retry,
|
|
72
74
|
this.deleteJob,
|
|
73
75
|
this.fail,
|
|
74
76
|
this.fetch,
|
|
@@ -516,6 +518,14 @@ class Manager extends EventEmitter {
|
|
|
516
518
|
return this.mapCommandResponse(ids, result)
|
|
517
519
|
}
|
|
518
520
|
|
|
521
|
+
async retry (name, id, options = {}) {
|
|
522
|
+
Attorney.assertQueueName(name)
|
|
523
|
+
const db = options.db || this.db
|
|
524
|
+
const ids = this.mapCompletionIdArg(id, 'resume')
|
|
525
|
+
const result = await db.executeSql(this.retryJobsCommand, [name, ids])
|
|
526
|
+
return this.mapCommandResponse(ids, result)
|
|
527
|
+
}
|
|
528
|
+
|
|
519
529
|
async createQueue (name, options = {}) {
|
|
520
530
|
name = name || options.name
|
|
521
531
|
|
package/src/plans.js
CHANGED
|
@@ -29,6 +29,7 @@ module.exports = {
|
|
|
29
29
|
cancelJobs,
|
|
30
30
|
resumeJobs,
|
|
31
31
|
deleteJobs,
|
|
32
|
+
retryJobs,
|
|
32
33
|
failJobsById,
|
|
33
34
|
failJobsByTimeout,
|
|
34
35
|
insertJob,
|
|
@@ -140,7 +141,7 @@ function createTableQueue (schema) {
|
|
|
140
141
|
partition_name text,
|
|
141
142
|
created_on timestamp with time zone not null default now(),
|
|
142
143
|
updated_on timestamp with time zone not null default now(),
|
|
143
|
-
PRIMARY KEY (name)
|
|
144
|
+
PRIMARY KEY (name)
|
|
144
145
|
)
|
|
145
146
|
`
|
|
146
147
|
}
|
|
@@ -208,7 +209,7 @@ const allJobColumns = `${baseJobColumns},
|
|
|
208
209
|
retry_count as "retryCount",
|
|
209
210
|
retry_delay as "retryDelay",
|
|
210
211
|
retry_backoff as "retryBackoff",
|
|
211
|
-
start_after as "startAfter",
|
|
212
|
+
start_after as "startAfter",
|
|
212
213
|
started_on as "startedOn",
|
|
213
214
|
singleton_key as "singletonKey",
|
|
214
215
|
singleton_on as "singletonOn",
|
|
@@ -263,7 +264,7 @@ function createQueueFunction (schema) {
|
|
|
263
264
|
END IF;
|
|
264
265
|
|
|
265
266
|
EXECUTE format('CREATE TABLE ${schema}.%I (LIKE ${schema}.job INCLUDING DEFAULTS)', table_name);
|
|
266
|
-
|
|
267
|
+
|
|
267
268
|
EXECUTE format('${formatPartitionCommand(createPrimaryKeyJob(schema))}', table_name);
|
|
268
269
|
EXECUTE format('${formatPartitionCommand(createQueueForeignKeyJob(schema))}', table_name);
|
|
269
270
|
EXECUTE format('${formatPartitionCommand(createQueueForeignKeyJobDeadLetter(schema))}', table_name);
|
|
@@ -292,7 +293,7 @@ function deleteQueueFunction (schema) {
|
|
|
292
293
|
$$
|
|
293
294
|
DECLARE
|
|
294
295
|
table_name varchar;
|
|
295
|
-
BEGIN
|
|
296
|
+
BEGIN
|
|
296
297
|
WITH deleted as (
|
|
297
298
|
DELETE FROM ${schema}.queue
|
|
298
299
|
WHERE name = queue_name
|
|
@@ -400,7 +401,7 @@ function updateQueue (schema) {
|
|
|
400
401
|
|
|
401
402
|
function getQueues (schema) {
|
|
402
403
|
return `
|
|
403
|
-
SELECT
|
|
404
|
+
SELECT
|
|
404
405
|
name,
|
|
405
406
|
policy,
|
|
406
407
|
retry_limit as "retryLimit",
|
|
@@ -503,13 +504,13 @@ function insertVersion (schema, version) {
|
|
|
503
504
|
}
|
|
504
505
|
|
|
505
506
|
function fetchNextJob (schema) {
|
|
506
|
-
return ({ includeMetadata, priority = true } = {}) => `
|
|
507
|
+
return ({ includeMetadata, priority = true, ignoreStartAfter = false } = {}) => `
|
|
507
508
|
WITH next as (
|
|
508
509
|
SELECT id
|
|
509
510
|
FROM ${schema}.job
|
|
510
511
|
WHERE name = $1
|
|
511
512
|
AND state < '${JOB_STATES.active}'
|
|
512
|
-
AND start_after < now()
|
|
513
|
+
${ignoreStartAfter ? '' : 'AND start_after < now()'}
|
|
513
514
|
ORDER BY ${priority ? 'priority desc, ' : ''}created_on, id
|
|
514
515
|
LIMIT $2
|
|
515
516
|
FOR UPDATE SKIP LOCKED
|
|
@@ -520,7 +521,7 @@ function fetchNextJob (schema) {
|
|
|
520
521
|
retry_count = CASE WHEN started_on IS NOT NULL THEN retry_count + 1 ELSE retry_count END
|
|
521
522
|
FROM next
|
|
522
523
|
WHERE name = $1 AND j.id = next.id
|
|
523
|
-
RETURNING j.${includeMetadata ? allJobColumns : baseJobColumns}
|
|
524
|
+
RETURNING j.${includeMetadata ? allJobColumns : baseJobColumns}
|
|
524
525
|
`
|
|
525
526
|
}
|
|
526
527
|
|
|
@@ -615,7 +616,7 @@ function failJobs (schema, where, output) {
|
|
|
615
616
|
END as completed_on,
|
|
616
617
|
keep_until,
|
|
617
618
|
dead_letter,
|
|
618
|
-
policy,
|
|
619
|
+
policy,
|
|
619
620
|
${output}
|
|
620
621
|
FROM deleted_jobs
|
|
621
622
|
ON CONFLICT DO NOTHING
|
|
@@ -726,7 +727,22 @@ function deleteJobs (schema) {
|
|
|
726
727
|
with results as (
|
|
727
728
|
DELETE FROM ${schema}.job
|
|
728
729
|
WHERE name = $1
|
|
729
|
-
AND id IN (SELECT UNNEST($2::uuid[]))
|
|
730
|
+
AND id IN (SELECT UNNEST($2::uuid[]))
|
|
731
|
+
RETURNING 1
|
|
732
|
+
)
|
|
733
|
+
SELECT COUNT(*) from results
|
|
734
|
+
`
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
function retryJobs (schema) {
|
|
738
|
+
return `
|
|
739
|
+
with results as (
|
|
740
|
+
UPDATE ${schema}.job
|
|
741
|
+
SET state = '${JOB_STATES.retry}',
|
|
742
|
+
retry_limit = retry_limit + 1
|
|
743
|
+
WHERE name = $1
|
|
744
|
+
AND id IN (SELECT UNNEST($2::uuid[]))
|
|
745
|
+
AND state = '${JOB_STATES.failed}'
|
|
730
746
|
RETURNING 1
|
|
731
747
|
)
|
|
732
748
|
SELECT COUNT(*) from results
|
|
@@ -813,7 +829,7 @@ function insertJob (schema) {
|
|
|
813
829
|
function insertJobs (schema) {
|
|
814
830
|
return `
|
|
815
831
|
WITH defaults as (
|
|
816
|
-
SELECT
|
|
832
|
+
SELECT
|
|
817
833
|
$2 as expire_in,
|
|
818
834
|
$3 as keep_until,
|
|
819
835
|
$4::int as retry_limit,
|
|
@@ -863,7 +879,7 @@ function insertJobs (schema) {
|
|
|
863
879
|
WHEN COALESCE("retryBackoff", q.retry_backoff, defaults.retry_backoff, false)
|
|
864
880
|
THEN GREATEST(COALESCE("retryDelay", q.retry_delay, defaults.retry_delay), 1)
|
|
865
881
|
ELSE COALESCE("retryDelay", q.retry_delay, defaults.retry_delay, 0)
|
|
866
|
-
END as retry_delay,
|
|
882
|
+
END as retry_delay,
|
|
867
883
|
COALESCE("retryBackoff", q.retry_backoff, defaults.retry_backoff, false) as retry_backoff,
|
|
868
884
|
q.policy
|
|
869
885
|
FROM (
|
|
@@ -886,7 +902,7 @@ function insertJobs (schema) {
|
|
|
886
902
|
"expireInSeconds" integer,
|
|
887
903
|
"keepUntil" timestamp with time zone,
|
|
888
904
|
"deadLetter" text
|
|
889
|
-
)
|
|
905
|
+
)
|
|
890
906
|
) j
|
|
891
907
|
JOIN ${schema}.queue q ON j.name = q.name,
|
|
892
908
|
defaults
|
package/types.d.ts
CHANGED
|
@@ -334,6 +334,9 @@ declare class PgBoss extends EventEmitter {
|
|
|
334
334
|
resume(name: string, id: string, options?: PgBoss.ConnectionOptions): Promise<void>;
|
|
335
335
|
resume(name: string, ids: string[], options?: PgBoss.ConnectionOptions): Promise<void>;
|
|
336
336
|
|
|
337
|
+
retry(name: string, id: string, options?: PgBoss.ConnectionOptions): Promise<void>;
|
|
338
|
+
retry(name: string, ids: string[], options?: PgBoss.ConnectionOptions): Promise<void>;
|
|
339
|
+
|
|
337
340
|
deleteJob(name: string, id: string, options?: PgBoss.ConnectionOptions): Promise<void>;
|
|
338
341
|
deleteJob(name: string, ids: string[], options?: PgBoss.ConnectionOptions): Promise<void>;
|
|
339
342
|
|