pg-boss 7.0.2 → 7.2.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
@@ -2,7 +2,7 @@ Queueing jobs in Node.js using PostgreSQL like a boss.
2
2
 
3
3
  [![PostgreSql Version](https://img.shields.io/badge/PostgreSQL-9.5+-blue.svg?maxAge=2592000)](http://www.postgresql.org)
4
4
  [![npm version](https://badge.fury.io/js/pg-boss.svg)](https://badge.fury.io/js/pg-boss)
5
- [![Build Status](https://travis-ci.com/timgit/pg-boss.svg?branch=master)](https://travis-ci.com/timgit/pg-boss)
5
+ [![Build Status](https://app.travis-ci.com/timgit/pg-boss.svg?branch=master)](https://app.travis-ci.com/github/timgit/pg-boss)
6
6
  [![Coverage Status](https://coveralls.io/repos/github/timgit/pg-boss/badge.svg?branch=master)](https://coveralls.io/github/timgit/pg-boss?branch=master)
7
7
 
8
8
  ```js
@@ -33,20 +33,20 @@ async function someAsyncJobHandler(job) {
33
33
 
34
34
  pg-boss is a job queue built in Node.js on top of PostgreSQL in order to provide background processing and reliable asynchronous execution to Node.js applications.
35
35
 
36
- pg-boss relies on [SKIP LOCKED](http://blog.2ndquadrant.com/what-is-select-skip-locked-for-in-postgresql-9-5), a feature introduced in PostgreSQL 9.5 written specifically for message queues, in order to resolve record locking challenges inherent with relational databases. This brings the safety of guaranteed atomic commits of a relational database to your asynchronous job processing.
36
+ pg-boss relies on [SKIP LOCKED](http://blog.2ndquadrant.com/what-is-select-skip-locked-for-in-postgresql-9-5), a feature added to postgres specifically for message queues, in order to resolve record locking challenges inherent with relational databases. This brings the safety of guaranteed atomic commits of a relational database to your asynchronous job processing.
37
37
 
38
38
  This will likely cater the most to teams already familiar with the simplicity of relational database semantics and operations (SQL, querying, and backups). It will be especially useful to those already relying on PostgreSQL that want to limit how many systems are required to monitor and support in their architecture.
39
39
 
40
40
  ## Features
41
- * Backpressure-compatible workers for polling queues
42
- * Distributed cron-based job scheduling with database clock synchronization
41
+ * Exactly-once job delivery
42
+ * Backpressure-compatible polling workers
43
+ * Cron scheduling
43
44
  * Pub/sub API for fan-out queue relationships
44
- * Job deferral, retries (with exponential backoff), throttling, rate limiting, debouncing
45
- * Job completion hooks for orchestrations/sagas
46
- * Direct send, fetch and completion APIs for custom integrations
45
+ * Deferral, retries (with exponential backoff), rate limiting, debouncing
46
+ * Completion jobs for orchestrations/sagas
47
47
  * Direct table access for bulk loads via COPY or INSERT
48
- * Multi-master compatible when running multiple instances (for example, in a Kubernetes ReplicaSet)
49
- * Automatic provisioning of required storage
48
+ * Multi-master compatible (for example, in a Kubernetes ReplicaSet)
49
+ * Automatic creation and migration of storage tables
50
50
  * Automatic maintenance operations to manage table growth
51
51
 
52
52
  ## Requirements
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pg-boss",
3
- "version": "7.0.2",
3
+ "version": "7.2.0",
4
4
  "description": "Queueing jobs in Node.js using PostgreSQL like a boss",
5
5
  "main": "./src/index.js",
6
6
  "engines": {
package/src/index.js CHANGED
@@ -73,12 +73,14 @@ class PgBoss extends EventEmitter {
73
73
 
74
74
  function promoteFunction (obj, func) {
75
75
  this[func.name] = (...args) => {
76
- if (this.stopped || this.stoppingOn) {
77
- const state = this.stoppingOn ? 'stopping' : 'stopped'
76
+ const shouldRun = !this.started || !((func.name === 'work' || func.name === 'onComplete') && (this.stopped || this.stoppingOn))
77
+
78
+ if (shouldRun) {
79
+ return func.apply(obj, args)
80
+ } else {
81
+ const state = this.stoppingOn ? 'stopping' : this.stopped ? 'stopped' : !this.started ? 'not started' : 'started'
78
82
  return Promise.reject(new Error(`pg-boss is ${state}.`))
79
83
  }
80
-
81
- return func.apply(obj, args)
82
84
  }
83
85
  }
84
86
 
@@ -100,6 +102,8 @@ class PgBoss extends EventEmitter {
100
102
 
101
103
  await this.contractor.start()
102
104
 
105
+ this.started = true
106
+
103
107
  this.manager.start()
104
108
 
105
109
  if (!this.config.noSupervisor) {
@@ -132,10 +136,6 @@ class PgBoss extends EventEmitter {
132
136
  await this.timekeeper.stop()
133
137
 
134
138
  const shutdown = async () => {
135
- if (this.db.isOurs) {
136
- await this.db.close()
137
- }
138
-
139
139
  this.stopped = true
140
140
  this.stoppingOn = null
141
141
 
package/src/manager.js CHANGED
@@ -56,6 +56,7 @@ class Manager extends EventEmitter {
56
56
  this.insertJobsCommand = plans.insertJobs(config.schema)
57
57
  this.completeJobsCommand = plans.completeJobs(config.schema)
58
58
  this.cancelJobsCommand = plans.cancelJobs(config.schema)
59
+ this.resumeJobsCommand = plans.resumeJobs(config.schema)
59
60
  this.failJobsCommand = plans.failJobs(config.schema)
60
61
  this.getJobByIdCommand = plans.getJobById(config.schema)
61
62
  this.getArchivedJobByIdCommand = plans.getArchivedJobById(config.schema)
@@ -67,6 +68,7 @@ class Manager extends EventEmitter {
67
68
  this.functions = [
68
69
  this.complete,
69
70
  this.cancel,
71
+ this.resume,
70
72
  this.fail,
71
73
  this.fetch,
72
74
  this.fetchCompleted,
@@ -541,6 +543,12 @@ class Manager extends EventEmitter {
541
543
  return this.mapCompletionResponse(ids, result)
542
544
  }
543
545
 
546
+ async resume (id) {
547
+ const ids = this.mapCompletionIdArg(id, 'resume')
548
+ const result = await this.db.executeSql(this.resumeJobsCommand, [ids])
549
+ return this.mapCompletionResponse(ids, result)
550
+ }
551
+
544
552
  async deleteQueue (queue, options) {
545
553
  assert(queue, 'Missing queue name argument')
546
554
  const sql = plans.deleteQueue(this.config.schema, options)
package/src/plans.js CHANGED
@@ -26,6 +26,7 @@ module.exports = {
26
26
  fetchNextJob,
27
27
  completeJobs,
28
28
  cancelJobs,
29
+ resumeJobs,
29
30
  failJobs,
30
31
  insertJob,
31
32
  insertJobs,
@@ -497,6 +498,19 @@ function cancelJobs (schema) {
497
498
  `
498
499
  }
499
500
 
501
+ function resumeJobs (schema) {
502
+ return `
503
+ with results as (
504
+ UPDATE ${schema}.job
505
+ SET completedOn = NULL,
506
+ state = '${states.created}'
507
+ WHERE id IN (SELECT UNNEST($1::uuid[]))
508
+ RETURNING 1
509
+ )
510
+ SELECT COUNT(*) from results
511
+ `
512
+ }
513
+
500
514
  function insertJob (schema) {
501
515
  return `
502
516
  INSERT INTO ${schema}.job (
package/types.d.ts CHANGED
@@ -203,7 +203,7 @@ declare namespace PgBoss {
203
203
  done: JobDoneCallback<ResData>;
204
204
  }
205
205
 
206
- interface MonitorStates {
206
+ interface MonitorState {
207
207
  all: number;
208
208
  created: number;
209
209
  retry: number;
@@ -212,7 +212,10 @@ declare namespace PgBoss {
212
212
  expired: number;
213
213
  cancelled: number;
214
214
  failed: number;
215
- queues: object;
215
+ }
216
+
217
+ interface MonitorStates extends MonitorState {
218
+ queues: { [queueName: string]: MonitorState };
216
219
  }
217
220
 
218
221
  interface Worker {
@@ -326,6 +329,9 @@ declare class PgBoss extends EventEmitter {
326
329
  cancel(id: string): Promise<void>;
327
330
  cancel(ids: string[]): Promise<void>;
328
331
 
332
+ resume(id: string): Promise<void>;
333
+ resume(ids: string[]): Promise<void>;
334
+
329
335
  complete(id: string): Promise<void>;
330
336
  complete(id: string, data: object): Promise<void>;
331
337
  complete(ids: string[]): Promise<void>;