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 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.1.6",
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.13.0",
11
+ "pg": "^8.16.0",
12
12
  "serialize-error": "^8.1.0"
13
13
  },
14
14
  "devDependencies": {
15
- "@types/node": "^20.16.9",
16
- "luxon": "^3.5.0",
17
- "mocha": "^10.7.3",
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