pg-boss 7.4.0 → 8.1.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
@@ -50,7 +50,7 @@ This will likely cater the most to teams already familiar with the simplicity of
50
50
  * Automatic maintenance operations to manage table growth
51
51
 
52
52
  ## Requirements
53
- * Node 12 or higher
53
+ * Node 14 or higher
54
54
  * PostgreSQL 9.5 or higher
55
55
 
56
56
  ## Installation
package/package.json CHANGED
@@ -1,31 +1,34 @@
1
1
  {
2
2
  "name": "pg-boss",
3
- "version": "7.4.0",
3
+ "version": "8.1.0",
4
4
  "description": "Queueing jobs in Node.js using PostgreSQL like a boss",
5
5
  "main": "./src/index.js",
6
6
  "engines": {
7
- "node": ">=12.0.0"
7
+ "node": ">=14"
8
8
  },
9
9
  "dependencies": {
10
10
  "cron-parser": "^4.0.0",
11
11
  "delay": "^5.0.0",
12
12
  "lodash.debounce": "^4.0.8",
13
- "p-map": "^4.0.0",
13
+ "p-map": "^5.3.0",
14
14
  "pg": "^8.5.1",
15
- "uuid": "^8.3.2"
15
+ "serialize-error": "^11.0.0",
16
+ "uuid": "^9.0.0"
16
17
  },
17
18
  "devDependencies": {
18
- "@types/node": "^17.0.2",
19
+ "@types/node": "^18.0.0",
19
20
  "coveralls": "^3.1.0",
20
- "luxon": "^2.0.1",
21
- "mocha": "^9.0.1",
21
+ "luxon": "^3.0.1",
22
+ "mocha": "^10.0.0",
22
23
  "nyc": "^15.1.0",
23
- "standard": "^16.0.3"
24
+ "standard": "^17.0.0"
24
25
  },
25
26
  "scripts": {
26
27
  "test": "standard && mocha",
27
28
  "cover": "nyc --reporter=text npm test",
28
- "forcover": "npm run cover && nyc report --reporter=text-lcov | coveralls",
29
+ "travis-cover": "nyc --reporter=text npm run travis-test",
30
+ "travis-test": "standard && mocha --jobs 0 --exit",
31
+ "forcover": "npm run travis-cover && nyc report --reporter=text-lcov | coveralls",
29
32
  "export-schema": "node ./scripts/construct.js",
30
33
  "export-migration": "node ./scripts/migrate.js",
31
34
  "export-rollback": "node ./scripts/rollback.js",
package/src/attorney.js CHANGED
@@ -377,7 +377,7 @@ function applyMonitoringConfig (config) {
377
377
 
378
378
  function applyUuidConfig (config) {
379
379
  assert(!('uuid' in config) || config.uuid === 'v1' || config.uuid === 'v4', 'configuration assert: uuid option only supports v1 or v4')
380
- config.uuid = config.uuid || 'v1'
380
+ config.uuid = config.uuid || 'v4'
381
381
  }
382
382
 
383
383
  function warnClockSkew (message) {
package/src/index.js CHANGED
@@ -90,6 +90,8 @@ class PgBoss extends EventEmitter {
90
90
  }
91
91
 
92
92
  async start () {
93
+ const { serializeError } = await import('serialize-error')
94
+
93
95
  if (!this.stopped) {
94
96
  return this
95
97
  }
@@ -104,7 +106,7 @@ class PgBoss extends EventEmitter {
104
106
 
105
107
  this.started = true
106
108
 
107
- this.manager.start()
109
+ this.manager.start({ stringify: serializeError })
108
110
 
109
111
  if (!this.config.noSupervisor) {
110
112
  await this.boss.supervise()
package/src/manager.js CHANGED
@@ -1,6 +1,5 @@
1
1
  const assert = require('assert')
2
2
  const EventEmitter = require('events')
3
- const pMap = require('p-map')
4
3
  const delay = require('delay')
5
4
  const uuid = require('uuid')
6
5
  const debounce = require('lodash.debounce')
@@ -45,6 +44,8 @@ class Manager extends EventEmitter {
45
44
  constructor (db, config) {
46
45
  super()
47
46
 
47
+ this.stringify = null
48
+
48
49
  this.config = config
49
50
  this.db = db
50
51
 
@@ -97,7 +98,8 @@ class Manager extends EventEmitter {
97
98
  this.emitWipThrottled = debounce(() => this.emit(events.wip, this.getWipData()), WIP_EVENT_INTERVAL, WIP_DEBOUNCE_OPTIONS)
98
99
  }
99
100
 
100
- start () {
101
+ start ({ stringify }) {
102
+ this.stringify = stringify
101
103
  this.stopping = false
102
104
  }
103
105
 
@@ -211,6 +213,8 @@ class Manager extends EventEmitter {
211
213
  const fetch = () => this.fetch(name, batchSize || (teamSize - queueSize), { includeMetadata })
212
214
 
213
215
  const onFetch = async (jobs) => {
216
+ const { default: pMap } = await import('p-map')
217
+
214
218
  if (this.config.__test__throw_worker) {
215
219
  throw new Error('__test__throw_worker')
216
220
  }
@@ -393,6 +397,7 @@ class Manager extends EventEmitter {
393
397
 
394
398
  async createJob (name, data, options, singletonOffset = 0) {
395
399
  const {
400
+ db: wrapper,
396
401
  expireIn,
397
402
  priority,
398
403
  startAfter,
@@ -423,8 +428,8 @@ class Manager extends EventEmitter {
423
428
  keepUntil, // 13
424
429
  onComplete // 14
425
430
  ]
426
-
427
- const result = await this.db.executeSql(this.insertJobCommand, values)
431
+ const db = wrapper || this.db
432
+ const result = await db.executeSql(this.insertJobCommand, values)
428
433
 
429
434
  if (result && result.rowCount === 1) {
430
435
  return result.rows[0].id
@@ -445,10 +450,12 @@ class Manager extends EventEmitter {
445
450
  return await this.createJob(name, data, options, singletonOffset)
446
451
  }
447
452
 
448
- async insert (jobs) {
453
+ async insert (jobs, options = {}) {
454
+ const { db: wrapper } = options
455
+ const db = wrapper || this.db
449
456
  const checkedJobs = Attorney.checkInsertArgs(jobs)
450
457
  const data = JSON.stringify(checkedJobs)
451
- return await this.db.executeSql(this.insertJobsCommand, [data])
458
+ return await db.executeSql(this.insertJobsCommand, [data])
452
459
  }
453
460
 
454
461
  getDebounceStartAfter (singletonSeconds, clockOffset) {
@@ -470,8 +477,8 @@ class Manager extends EventEmitter {
470
477
 
471
478
  async fetch (name, batchSize, options = {}) {
472
479
  const values = Attorney.checkFetchArgs(name, batchSize, options)
473
-
474
- const result = await this.db.executeSql(
480
+ const db = options.db || this.db
481
+ const result = await db.executeSql(
475
482
  this.nextJobCommand(options.includeMetadata || false),
476
483
  [values.name, batchSize || 1]
477
484
  )
@@ -513,15 +520,11 @@ class Manager extends EventEmitter {
513
520
  mapCompletionDataArg (data) {
514
521
  if (data === null || typeof data === 'undefined' || typeof data === 'function') { return null }
515
522
 
516
- if (data instanceof Error) {
517
- const newData = {}
518
- Object.getOwnPropertyNames(data).forEach(key => { newData[key] = data[key] })
519
- data = newData
520
- }
521
-
522
- return (typeof data === 'object' && !Array.isArray(data))
523
+ const result = (typeof data === 'object' && !Array.isArray(data))
523
524
  ? data
524
525
  : { value: data }
526
+
527
+ return this.stringify(result)
525
528
  }
526
529
 
527
530
  mapCompletionResponse (ids, result) {
@@ -532,27 +535,31 @@ class Manager extends EventEmitter {
532
535
  }
533
536
  }
534
537
 
535
- async complete (id, data) {
538
+ async complete (id, data, options = {}) {
539
+ const db = options.db || this.db
536
540
  const ids = this.mapCompletionIdArg(id, 'complete')
537
- const result = await this.db.executeSql(this.completeJobsCommand, [ids, this.mapCompletionDataArg(data)])
541
+ const result = await db.executeSql(this.completeJobsCommand, [ids, this.mapCompletionDataArg(data)])
538
542
  return this.mapCompletionResponse(ids, result)
539
543
  }
540
544
 
541
- async fail (id, data) {
545
+ async fail (id, data, options = {}) {
546
+ const db = options.db || this.db
542
547
  const ids = this.mapCompletionIdArg(id, 'fail')
543
- const result = await this.db.executeSql(this.failJobsCommand, [ids, this.mapCompletionDataArg(data)])
548
+ const result = await db.executeSql(this.failJobsCommand, [ids, this.mapCompletionDataArg(data)])
544
549
  return this.mapCompletionResponse(ids, result)
545
550
  }
546
551
 
547
- async cancel (id) {
552
+ async cancel (id, options = {}) {
553
+ const db = options.db || this.db
548
554
  const ids = this.mapCompletionIdArg(id, 'cancel')
549
- const result = await this.db.executeSql(this.cancelJobsCommand, [ids])
555
+ const result = await db.executeSql(this.cancelJobsCommand, [ids])
550
556
  return this.mapCompletionResponse(ids, result)
551
557
  }
552
558
 
553
- async resume (id) {
559
+ async resume (id, options = {}) {
560
+ const db = options.db || this.db
554
561
  const ids = this.mapCompletionIdArg(id, 'resume')
555
- const result = await this.db.executeSql(this.resumeJobsCommand, [ids])
562
+ const result = await db.executeSql(this.resumeJobsCommand, [ids])
556
563
  return this.mapCompletionResponse(ids, result)
557
564
  }
558
565
 
@@ -584,14 +591,15 @@ class Manager extends EventEmitter {
584
591
  return result ? parseFloat(result.rows[0].count) : null
585
592
  }
586
593
 
587
- async getJobById (id) {
588
- const result1 = await this.db.executeSql(this.getJobByIdCommand, [id])
594
+ async getJobById (id, options = {}) {
595
+ const db = options.db || this.db
596
+ const result1 = await db.executeSql(this.getJobByIdCommand, [id])
589
597
 
590
598
  if (result1 && result1.rows && result1.rows.length === 1) {
591
599
  return result1.rows[0]
592
600
  }
593
601
 
594
- const result2 = await this.db.executeSql(this.getArchivedJobByIdCommand, [id])
602
+ const result2 = await db.executeSql(this.getArchivedJobByIdCommand, [id])
595
603
 
596
604
  if (result2 && result2.rows && result2.rows.length === 1) {
597
605
  return result2.rows[0]
package/src/plans.js CHANGED
@@ -69,6 +69,7 @@ function locked (schema, query) {
69
69
 
70
70
  return `
71
71
  BEGIN;
72
+ SET LOCAL statement_timeout = '30s';
72
73
  ${advisoryLock(schema)};
73
74
  ${query};
74
75
  COMMIT;
package/src/timekeeper.js CHANGED
@@ -1,4 +1,3 @@
1
- const pMap = require('p-map')
2
1
  const EventEmitter = require('events')
3
2
  const plans = require('./plans')
4
3
  const cronParser = require('cron-parser')
@@ -126,6 +125,8 @@ class Timekeeper extends EventEmitter {
126
125
  async onCron () {
127
126
  if (this.stopped) return
128
127
 
128
+ const { default: pMap } = await import('p-map')
129
+
129
130
  try {
130
131
  if (this.config.__test__throw_clock_monitoring) {
131
132
  throw new Error('clock monitoring error')
package/types.d.ts CHANGED
@@ -91,7 +91,13 @@ declare namespace PgBoss {
91
91
  singletonNextSlot?: boolean;
92
92
  }
93
93
 
94
- type SendOptions = JobOptions & ExpirationOptions & RetentionOptions & RetryOptions & CompletionOptions
94
+ interface ConnectionOptions {
95
+ db?: Db;
96
+ }
97
+
98
+ type InsertOptions = ConnectionOptions;
99
+
100
+ type SendOptions = JobOptions & ExpirationOptions & RetentionOptions & RetryOptions & CompletionOptions & ConnectionOptions;
95
101
 
96
102
  type ScheduleOptions = SendOptions & { tz?: string }
97
103
 
@@ -112,7 +118,7 @@ declare namespace PgBoss {
112
118
 
113
119
  type FetchOptions = {
114
120
  includeMetadata?: boolean;
115
- }
121
+ } & ConnectionOptions;
116
122
 
117
123
  interface WorkHandler<ReqData, ResData> {
118
124
  (job: PgBoss.JobWithDoneCallback<ReqData, ResData>): Promise<ResData> | void;
@@ -190,7 +196,7 @@ declare namespace PgBoss {
190
196
  retryLimit?: number;
191
197
  retryDelay?: number;
192
198
  retryBackoff?: boolean;
193
- startAfter?: Date | string;
199
+ startAfter?: Date | string;
194
200
  singletonKey?: string;
195
201
  expireInSeconds?: number;
196
202
  keepUntil?: Date | string;
@@ -298,6 +304,7 @@ declare class PgBoss extends EventEmitter {
298
304
  sendDebounced(name: string, data: object, options: PgBoss.SendOptions, seconds: number, key: string): Promise<string | null>;
299
305
 
300
306
  insert(jobs: PgBoss.JobInsert[]): Promise<void>;
307
+ insert(jobs: PgBoss.JobInsert[], options: PgBoss.InsertOptions): Promise<void>;
301
308
 
302
309
  work<ReqData, ResData>(name: string, handler: PgBoss.WorkHandler<ReqData, ResData>): Promise<string>;
303
310
  work<ReqData, ResData>(name: string, options: PgBoss.WorkOptions & { includeMetadata: true }, handler: PgBoss.WorkWithMetadataHandler<ReqData, ResData>): Promise<string>;
@@ -311,7 +318,7 @@ declare class PgBoss extends EventEmitter {
311
318
 
312
319
  /**
313
320
  * Notify worker that something has changed
314
- * @param workerId
321
+ * @param workerId
315
322
  */
316
323
  notifyWorker(workerId: string): void;
317
324
 
@@ -334,22 +341,22 @@ declare class PgBoss extends EventEmitter {
334
341
  fetchCompleted<T>(name: string, batchSize: number, options: PgBoss.FetchOptions & { includeMetadata: true }): Promise<PgBoss.JobWithMetadata<T>[] | null>;
335
342
  fetchCompleted<T>(name: string, batchSize: number, options: PgBoss.FetchOptions): Promise<PgBoss.Job<T>[] | null>;
336
343
 
337
- cancel(id: string): Promise<void>;
338
- cancel(ids: string[]): Promise<void>;
344
+ cancel(id: string, options: PgBoss.ConnectionOptions): Promise<void>;
345
+ cancel(ids: string[], options: PgBoss.ConnectionOptions): Promise<void>;
339
346
 
340
- resume(id: string): Promise<void>;
341
- resume(ids: string[]): Promise<void>;
347
+ resume(id: string, options: PgBoss.ConnectionOptions): Promise<void>;
348
+ resume(ids: string[], options: PgBoss.ConnectionOptions): Promise<void>;
342
349
 
343
- complete(id: string): Promise<void>;
344
- complete(id: string, data: object): Promise<void>;
345
- complete(ids: string[]): Promise<void>;
350
+ complete(id: string, options: PgBoss.ConnectionOptions): Promise<void>;
351
+ complete(id: string, data: object, options: PgBoss.ConnectionOptions): Promise<void>;
352
+ complete(ids: string[], options: PgBoss.ConnectionOptions): Promise<void>;
346
353
 
347
- fail(id: string): Promise<void>;
348
- fail(id: string, data: object): Promise<void>;
349
- fail(ids: string[]): Promise<void>;
354
+ fail(id: string, options: PgBoss.ConnectionOptions): Promise<void>;
355
+ fail(id: string, data: object, options: PgBoss.ConnectionOptions): Promise<void>;
356
+ fail(ids: string[], options: PgBoss.ConnectionOptions): Promise<void>;
350
357
 
351
358
  getQueueSize(name: string, options?: object): Promise<number>;
352
- getJobById(id: string): Promise<PgBoss.JobWithMetadata | null>;
359
+ getJobById(id: string, options: PgBoss.ConnectionOptions): Promise<PgBoss.JobWithMetadata | null>;
353
360
 
354
361
  deleteQueue(name: string): Promise<void>;
355
362
  deleteAllQueues(): Promise<void>;