pg-boss 10.0.0-beta5 → 10.0.0-beta7
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/package.json +1 -1
- package/src/attorney.js +4 -4
- package/src/boss.js +9 -20
- package/src/contractor.js +5 -5
- package/src/db.js +0 -26
- package/src/manager.js +10 -15
- package/src/plans.js +149 -151
- package/src/timekeeper.js +14 -35
- package/types.d.ts +31 -25
package/package.json
CHANGED
package/src/attorney.js
CHANGED
|
@@ -152,6 +152,10 @@ function getConfig (value) {
|
|
|
152
152
|
? { connectionString: value }
|
|
153
153
|
: { ...value }
|
|
154
154
|
|
|
155
|
+
config.schedule = ('schedule' in config) ? config.schedule : true
|
|
156
|
+
config.supervise = ('supervise' in config) ? config.supervise : true
|
|
157
|
+
config.migrate = ('migrate' in config) ? config.migrate : true
|
|
158
|
+
|
|
155
159
|
applySchemaConfig(config)
|
|
156
160
|
applyMaintenanceConfig(config)
|
|
157
161
|
applyArchiveConfig(config)
|
|
@@ -303,10 +307,6 @@ function applyMaintenanceConfig (config) {
|
|
|
303
307
|
: 120
|
|
304
308
|
|
|
305
309
|
assert(config.maintenanceIntervalSeconds / 60 / 60 < MAX_INTERVAL_HOURS, `configuration assert: maintenance interval cannot exceed ${MAX_INTERVAL_HOURS} hours`)
|
|
306
|
-
|
|
307
|
-
config.schedule = ('schedule' in config) ? config.schedule : true
|
|
308
|
-
config.supervise = ('supervise' in config) ? config.supervise : true
|
|
309
|
-
config.migrate = ('migrate' in config) ? config.migrate : true
|
|
310
310
|
}
|
|
311
311
|
|
|
312
312
|
function applyDeleteConfig (config) {
|
package/src/boss.js
CHANGED
|
@@ -24,10 +24,8 @@ class Boss extends EventEmitter {
|
|
|
24
24
|
this.failJobsByTimeoutCommand = plans.locked(config.schema, plans.failJobsByTimeout(config.schema))
|
|
25
25
|
this.archiveCommand = plans.locked(config.schema, plans.archive(config.schema, config.archiveInterval, config.archiveFailedInterval))
|
|
26
26
|
this.dropCommand = plans.locked(config.schema, plans.drop(config.schema, config.deleteAfter))
|
|
27
|
-
this.
|
|
28
|
-
this.
|
|
29
|
-
this.getMonitorTimeCommand = plans.getMonitorTime(config.schema)
|
|
30
|
-
this.setMonitorTimeCommand = plans.setMonitorTime(config.schema)
|
|
27
|
+
this.trySetMaintenanceTimeCommand = plans.trySetMaintenanceTime(config.schema)
|
|
28
|
+
this.trySetMonitorTimeCommand = plans.trySetMonitorTime(config.schema)
|
|
31
29
|
this.countStatesCommand = plans.countStates(config.schema)
|
|
32
30
|
|
|
33
31
|
this.functions = [
|
|
@@ -48,8 +46,6 @@ class Boss extends EventEmitter {
|
|
|
48
46
|
}
|
|
49
47
|
|
|
50
48
|
async onMonitor () {
|
|
51
|
-
let locker
|
|
52
|
-
|
|
53
49
|
try {
|
|
54
50
|
if (this.monitoring) {
|
|
55
51
|
return
|
|
@@ -65,26 +61,24 @@ class Boss extends EventEmitter {
|
|
|
65
61
|
throw new Error(this.config.__test__throw_monitor)
|
|
66
62
|
}
|
|
67
63
|
|
|
68
|
-
|
|
64
|
+
if (this.stopped) {
|
|
65
|
+
return
|
|
66
|
+
}
|
|
69
67
|
|
|
70
|
-
const {
|
|
68
|
+
const { rows } = await this.db.executeSql(this.trySetMonitorTimeCommand, [this.config.monitorStateIntervalSeconds])
|
|
71
69
|
|
|
72
|
-
if (
|
|
70
|
+
if (rows.length === 1 && !this.stopped) {
|
|
73
71
|
const states = await this.countStates()
|
|
74
|
-
this.setMonitorTime()
|
|
75
72
|
this.emit(events.monitorStates, states)
|
|
76
73
|
}
|
|
77
74
|
} catch (err) {
|
|
78
75
|
this.emit(events.error, err)
|
|
79
76
|
} finally {
|
|
80
|
-
await locker?.unlock()
|
|
81
77
|
this.monitoring = false
|
|
82
78
|
}
|
|
83
79
|
}
|
|
84
80
|
|
|
85
81
|
async onSupervise () {
|
|
86
|
-
let locker
|
|
87
|
-
|
|
88
82
|
try {
|
|
89
83
|
if (this.maintaining) {
|
|
90
84
|
return
|
|
@@ -105,18 +99,15 @@ class Boss extends EventEmitter {
|
|
|
105
99
|
return
|
|
106
100
|
}
|
|
107
101
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
const { secondsAgo } = await this.getMaintenanceTime()
|
|
102
|
+
const { rows } = await this.db.executeSql(this.trySetMaintenanceTimeCommand, [this.config.maintenanceIntervalSeconds])
|
|
111
103
|
|
|
112
|
-
if (
|
|
104
|
+
if (rows.length === 1 && !this.stopped) {
|
|
113
105
|
const result = await this.maintain()
|
|
114
106
|
this.emit(events.maintenance, result)
|
|
115
107
|
}
|
|
116
108
|
} catch (err) {
|
|
117
109
|
this.emit(events.error, err)
|
|
118
110
|
} finally {
|
|
119
|
-
await locker?.unlock()
|
|
120
111
|
this.maintaining = false
|
|
121
112
|
}
|
|
122
113
|
}
|
|
@@ -130,8 +121,6 @@ class Boss extends EventEmitter {
|
|
|
130
121
|
|
|
131
122
|
const ended = Date.now()
|
|
132
123
|
|
|
133
|
-
await this.setMaintenanceTime()
|
|
134
|
-
|
|
135
124
|
return { ms: ended - started }
|
|
136
125
|
}
|
|
137
126
|
|
package/src/contractor.js
CHANGED
|
@@ -24,26 +24,26 @@ class Contractor {
|
|
|
24
24
|
|
|
25
25
|
// exported api to index
|
|
26
26
|
this.functions = [
|
|
27
|
-
this.
|
|
27
|
+
this.schemaVersion,
|
|
28
28
|
this.isInstalled
|
|
29
29
|
]
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
async
|
|
32
|
+
async schemaVersion () {
|
|
33
33
|
const result = await this.db.executeSql(plans.getVersion(this.config.schema))
|
|
34
34
|
return result.rows.length ? parseInt(result.rows[0].version) : null
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
async isInstalled () {
|
|
38
38
|
const result = await this.db.executeSql(plans.versionTableExists(this.config.schema))
|
|
39
|
-
return result.rows
|
|
39
|
+
return !!result.rows[0].name
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
async start () {
|
|
43
43
|
const installed = await this.isInstalled()
|
|
44
44
|
|
|
45
45
|
if (installed) {
|
|
46
|
-
const version = await this.
|
|
46
|
+
const version = await this.schemaVersion()
|
|
47
47
|
|
|
48
48
|
if (schemaVersion > version) {
|
|
49
49
|
throw new Error('Migrations are not supported to v10')
|
|
@@ -61,7 +61,7 @@ class Contractor {
|
|
|
61
61
|
throw new Error('pg-boss is not installed')
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
const version = await this.
|
|
64
|
+
const version = await this.schemaVersion()
|
|
65
65
|
|
|
66
66
|
if (schemaVersion !== version) {
|
|
67
67
|
throw new Error('pg-boss database requires migrations')
|
package/src/db.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
const EventEmitter = require('events')
|
|
2
2
|
const pg = require('pg')
|
|
3
|
-
const { advisoryLock } = require('./plans')
|
|
4
3
|
|
|
5
4
|
class Db extends EventEmitter {
|
|
6
5
|
constructor (config) {
|
|
@@ -43,31 +42,6 @@ class Db extends EventEmitter {
|
|
|
43
42
|
return await this.pool.query(text, values)
|
|
44
43
|
}
|
|
45
44
|
}
|
|
46
|
-
|
|
47
|
-
async lock ({ timeout = 30, key } = {}) {
|
|
48
|
-
const lockedClient = await this.pool.connect()
|
|
49
|
-
|
|
50
|
-
const query = `
|
|
51
|
-
BEGIN;
|
|
52
|
-
SET LOCAL lock_timeout = '${timeout}s';
|
|
53
|
-
SET LOCAL idle_in_transaction_session_timeout = '${timeout}s';
|
|
54
|
-
${advisoryLock(this.config.schema, key)};
|
|
55
|
-
`
|
|
56
|
-
|
|
57
|
-
await lockedClient.query(query)
|
|
58
|
-
|
|
59
|
-
const locker = {
|
|
60
|
-
unlock: async function () {
|
|
61
|
-
try {
|
|
62
|
-
await lockedClient.query('COMMIT')
|
|
63
|
-
} finally {
|
|
64
|
-
lockedClient.release()
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
return locker
|
|
70
|
-
}
|
|
71
45
|
}
|
|
72
46
|
|
|
73
47
|
module.exports = Db
|
package/src/manager.js
CHANGED
|
@@ -217,7 +217,7 @@ class Manager extends EventEmitter {
|
|
|
217
217
|
this.emitWip(name)
|
|
218
218
|
|
|
219
219
|
if (batchSize) {
|
|
220
|
-
const maxExpiration = jobs.reduce((acc, i) => Math.max(acc, i.
|
|
220
|
+
const maxExpiration = jobs.reduce((acc, i) => Math.max(acc, i.expireInSeconds), 0)
|
|
221
221
|
|
|
222
222
|
await resolveWithinSeconds(Promise.all([callback(jobs)]), maxExpiration)
|
|
223
223
|
.then(() => this.complete(name, jobs.map(job => job.id)))
|
|
@@ -228,7 +228,7 @@ class Manager extends EventEmitter {
|
|
|
228
228
|
}
|
|
229
229
|
|
|
230
230
|
const allTeamPromise = pMap(jobs, job =>
|
|
231
|
-
resolveWithinSeconds(callback(job), job.
|
|
231
|
+
resolveWithinSeconds(callback(job), job.expireInSeconds)
|
|
232
232
|
.then(result => this.complete(name, job.id, result))
|
|
233
233
|
.catch(err => this.fail(name, job.id, err))
|
|
234
234
|
.then(() => refill ? onRefill() : null)
|
|
@@ -317,13 +317,9 @@ class Manager extends EventEmitter {
|
|
|
317
317
|
async publish (event, ...args) {
|
|
318
318
|
assert(event, 'Missing required argument')
|
|
319
319
|
|
|
320
|
-
const
|
|
320
|
+
const { rows } = await this.db.executeSql(this.getQueuesForEventCommand, [event])
|
|
321
321
|
|
|
322
|
-
|
|
323
|
-
return []
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
return await Promise.all(result.rows.map(({ name }) => this.send(name, ...args)))
|
|
322
|
+
return await Promise.all(rows.map(({ name }) => this.send(name, ...args)))
|
|
327
323
|
}
|
|
328
324
|
|
|
329
325
|
async send (...args) {
|
|
@@ -406,10 +402,10 @@ class Manager extends EventEmitter {
|
|
|
406
402
|
]
|
|
407
403
|
|
|
408
404
|
const db = wrapper || this.db
|
|
409
|
-
const
|
|
405
|
+
const { rows } = await db.executeSql(this.insertJobCommand, values)
|
|
410
406
|
|
|
411
|
-
if (
|
|
412
|
-
return
|
|
407
|
+
if (rows.length === 1) {
|
|
408
|
+
return rows[0].id
|
|
413
409
|
}
|
|
414
410
|
|
|
415
411
|
if (!options.singletonNextSlot) {
|
|
@@ -645,17 +641,16 @@ class Manager extends EventEmitter {
|
|
|
645
641
|
assert(name, 'Missing queue name argument')
|
|
646
642
|
|
|
647
643
|
const queueSql = plans.getQueueByName(this.config.schema)
|
|
648
|
-
const
|
|
644
|
+
const { rows } = await this.db.executeSql(queueSql, [name])
|
|
649
645
|
|
|
650
|
-
if (
|
|
646
|
+
if (rows.length) {
|
|
651
647
|
Attorney.assertQueueName(name)
|
|
652
648
|
const sql = plans.dropPartition(this.config.schema, name)
|
|
653
649
|
await this.db.executeSql(sql)
|
|
654
650
|
}
|
|
655
651
|
|
|
656
652
|
const sql = plans.deleteQueueRecords(this.config.schema)
|
|
657
|
-
|
|
658
|
-
return result2?.rowCount || null
|
|
653
|
+
await this.db.executeSql(sql, [name])
|
|
659
654
|
}
|
|
660
655
|
|
|
661
656
|
async purgeQueue (queue) {
|
package/src/plans.js
CHANGED
|
@@ -53,14 +53,10 @@ module.exports = {
|
|
|
53
53
|
getQueueSize,
|
|
54
54
|
purgeQueue,
|
|
55
55
|
clearStorage,
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
setMonitorTime,
|
|
60
|
-
getCronTime,
|
|
61
|
-
setCronTime,
|
|
56
|
+
trySetMaintenanceTime,
|
|
57
|
+
trySetMonitorTime,
|
|
58
|
+
trySetCronTime,
|
|
62
59
|
locked,
|
|
63
|
-
advisoryLock,
|
|
64
60
|
assertMigration,
|
|
65
61
|
getArchivedJobById,
|
|
66
62
|
getJobById,
|
|
@@ -77,7 +73,6 @@ function create (schema, version) {
|
|
|
77
73
|
createEnumJobState(schema),
|
|
78
74
|
|
|
79
75
|
createTableJob(schema),
|
|
80
|
-
createIndexJobName(schema),
|
|
81
76
|
createIndexJobFetch(schema),
|
|
82
77
|
createIndexJobPolicyStately(schema),
|
|
83
78
|
createIndexJobPolicyShort(schema),
|
|
@@ -89,7 +84,6 @@ function create (schema, version) {
|
|
|
89
84
|
createPrimaryKeyArchive(schema),
|
|
90
85
|
createColumnArchiveArchivedOn(schema),
|
|
91
86
|
createIndexArchiveArchivedOn(schema),
|
|
92
|
-
createIndexArchiveName(schema),
|
|
93
87
|
|
|
94
88
|
createTableVersion(schema),
|
|
95
89
|
createTableQueue(schema),
|
|
@@ -146,26 +140,44 @@ function createTableJob (schema) {
|
|
|
146
140
|
priority integer not null default(0),
|
|
147
141
|
data jsonb,
|
|
148
142
|
state ${schema}.job_state not null default('${states.created}'),
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
143
|
+
retry_limit integer not null default(0),
|
|
144
|
+
retry_count integer not null default(0),
|
|
145
|
+
retry_delay integer not null default(0),
|
|
146
|
+
retry_backoff boolean not null default false,
|
|
147
|
+
start_after timestamp with time zone not null default now(),
|
|
148
|
+
started_on timestamp with time zone,
|
|
149
|
+
singleton_key text,
|
|
150
|
+
singleton_on timestamp without time zone,
|
|
151
|
+
expire_in interval not null default interval '15 minutes',
|
|
152
|
+
created_on timestamp with time zone not null default now(),
|
|
153
|
+
completed_on timestamp with time zone,
|
|
154
|
+
keep_until timestamp with time zone NOT NULL default now() + interval '14 days',
|
|
161
155
|
output jsonb,
|
|
162
|
-
|
|
156
|
+
dead_letter text,
|
|
163
157
|
policy text,
|
|
164
158
|
CONSTRAINT job_pkey PRIMARY KEY (name, id)
|
|
165
159
|
) PARTITION BY LIST (name)
|
|
166
160
|
`
|
|
167
161
|
}
|
|
168
162
|
|
|
163
|
+
const baseJobColumns = 'id, name, data, EXTRACT(epoch FROM expire_in) as "expireInSeconds"'
|
|
164
|
+
const allJobColumns = `${baseJobColumns}, policy, state, priority,
|
|
165
|
+
retry_limit as "retryLimit",
|
|
166
|
+
retry_count as "retryCount",
|
|
167
|
+
retry_delay as "retryDelay",
|
|
168
|
+
retry_backoff as "retryBackoff",
|
|
169
|
+
start_after as "startAfter",
|
|
170
|
+
started_on as "startedOn",
|
|
171
|
+
singleton_key as "singletonKey",
|
|
172
|
+
singleton_on as "singletonOn",
|
|
173
|
+
expire_in as "expireIn",
|
|
174
|
+
created_on as "createdOn",
|
|
175
|
+
completed_on as "completedOn",
|
|
176
|
+
keep_until as "keepUntil",
|
|
177
|
+
dead_letter as "deadLetter",
|
|
178
|
+
output
|
|
179
|
+
`
|
|
180
|
+
|
|
169
181
|
function createPartition (schema, name) {
|
|
170
182
|
return `SELECT ${schema}.create_partition('${name}');`
|
|
171
183
|
}
|
|
@@ -232,19 +244,15 @@ function createIndexJobPolicyStately (schema) {
|
|
|
232
244
|
}
|
|
233
245
|
|
|
234
246
|
function createIndexJobThrottleOn (schema) {
|
|
235
|
-
return `CREATE UNIQUE INDEX job_throttle_on ON ${schema}.job (name,
|
|
247
|
+
return `CREATE UNIQUE INDEX job_throttle_on ON ${schema}.job (name, singleton_on, COALESCE(singleton_key, '')) WHERE state <= '${states.completed}' AND singleton_on IS NOT NULL`
|
|
236
248
|
}
|
|
237
249
|
|
|
238
250
|
function createIndexJobThrottleKey (schema) {
|
|
239
|
-
return `CREATE UNIQUE INDEX job_throttle_key ON ${schema}.job (name,
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
function createIndexJobName (schema) {
|
|
243
|
-
return `CREATE INDEX job_name ON ${schema}.job (name)`
|
|
251
|
+
return `CREATE UNIQUE INDEX job_throttle_key ON ${schema}.job (name, singleton_key) WHERE state <= '${states.completed}' AND singleton_on IS NULL`
|
|
244
252
|
}
|
|
245
253
|
|
|
246
254
|
function createIndexJobFetch (schema) {
|
|
247
|
-
return `CREATE INDEX job_fetch ON ${schema}.job (name,
|
|
255
|
+
return `CREATE INDEX job_fetch ON ${schema}.job (name, start_after) INCLUDE (priority, created_on, id) WHERE state < '${states.active}'`
|
|
248
256
|
}
|
|
249
257
|
|
|
250
258
|
function createTableArchive (schema) {
|
|
@@ -252,40 +260,31 @@ function createTableArchive (schema) {
|
|
|
252
260
|
}
|
|
253
261
|
|
|
254
262
|
function createColumnArchiveArchivedOn (schema) {
|
|
255
|
-
return `ALTER TABLE ${schema}.archive ADD
|
|
263
|
+
return `ALTER TABLE ${schema}.archive ADD archived_on timestamptz NOT NULL DEFAULT now()`
|
|
256
264
|
}
|
|
257
265
|
|
|
258
266
|
function createIndexArchiveArchivedOn (schema) {
|
|
259
|
-
return `CREATE INDEX
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
function createIndexArchiveName (schema) {
|
|
263
|
-
return `CREATE INDEX archive_name_idx ON ${schema}.archive(name)`
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
function getMaintenanceTime (schema) {
|
|
267
|
-
return `SELECT maintained_on, EXTRACT( EPOCH FROM (now() - maintained_on) ) seconds_ago FROM ${schema}.version`
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
function setMaintenanceTime (schema) {
|
|
271
|
-
return `UPDATE ${schema}.version SET maintained_on = now()`
|
|
267
|
+
return `CREATE INDEX archive_archived_on_idx ON ${schema}.archive(archived_on)`
|
|
272
268
|
}
|
|
273
269
|
|
|
274
|
-
function
|
|
275
|
-
return
|
|
270
|
+
function trySetMaintenanceTime (schema) {
|
|
271
|
+
return trySetTimestamp(schema, 'maintained_on')
|
|
276
272
|
}
|
|
277
273
|
|
|
278
|
-
function
|
|
279
|
-
return
|
|
274
|
+
function trySetMonitorTime (schema) {
|
|
275
|
+
return trySetTimestamp(schema, 'monitored_on')
|
|
280
276
|
}
|
|
281
277
|
|
|
282
|
-
function
|
|
283
|
-
|
|
284
|
-
return `UPDATE ${schema}.version SET cron_on = ${time}`
|
|
278
|
+
function trySetCronTime (schema) {
|
|
279
|
+
return trySetTimestamp(schema, 'cron_on')
|
|
285
280
|
}
|
|
286
281
|
|
|
287
|
-
function
|
|
288
|
-
return `
|
|
282
|
+
function trySetTimestamp (schema, column) {
|
|
283
|
+
return `
|
|
284
|
+
UPDATE ${schema}.version SET ${column} = now()
|
|
285
|
+
WHERE EXTRACT( EPOCH FROM (now() - COALESCE(${column}, now() - interval '1 week') ) ) > $1
|
|
286
|
+
RETURNING true
|
|
287
|
+
`
|
|
289
288
|
}
|
|
290
289
|
|
|
291
290
|
function createQueue (schema) {
|
|
@@ -458,19 +457,18 @@ function fetchNextJob (schema) {
|
|
|
458
457
|
FROM ${schema}.job
|
|
459
458
|
WHERE name = $1
|
|
460
459
|
AND state < '${states.active}'
|
|
461
|
-
AND
|
|
462
|
-
ORDER BY ${priority && 'priority desc, '}
|
|
460
|
+
AND start_after < now()
|
|
461
|
+
ORDER BY ${priority && 'priority desc, '} created_on, id
|
|
463
462
|
LIMIT $2
|
|
464
463
|
FOR UPDATE SKIP LOCKED
|
|
465
464
|
)
|
|
466
465
|
UPDATE ${schema}.job j SET
|
|
467
466
|
state = '${states.active}',
|
|
468
|
-
|
|
469
|
-
|
|
467
|
+
started_on = now(),
|
|
468
|
+
retry_count = CASE WHEN started_on IS NOT NULL THEN retry_count + 1 ELSE retry_count END
|
|
470
469
|
FROM next
|
|
471
470
|
WHERE name = $1 AND j.id = next.id
|
|
472
|
-
RETURNING
|
|
473
|
-
EXTRACT(epoch FROM expireIn) as expire_in_seconds
|
|
471
|
+
RETURNING j.${includeMetadata ? allJobColumns : baseJobColumns}
|
|
474
472
|
`
|
|
475
473
|
}
|
|
476
474
|
|
|
@@ -478,7 +476,7 @@ function completeJobs (schema) {
|
|
|
478
476
|
return `
|
|
479
477
|
WITH results AS (
|
|
480
478
|
UPDATE ${schema}.job
|
|
481
|
-
SET
|
|
479
|
+
SET completed_on = now(),
|
|
482
480
|
state = '${states.completed}',
|
|
483
481
|
output = $3::jsonb
|
|
484
482
|
WHERE name = $1
|
|
@@ -498,7 +496,7 @@ function failJobsById (schema) {
|
|
|
498
496
|
}
|
|
499
497
|
|
|
500
498
|
function failJobsByTimeout (schema) {
|
|
501
|
-
const where = `state = '${states.active}' AND (
|
|
499
|
+
const where = `state = '${states.active}' AND (started_on + expire_in) < now()`
|
|
502
500
|
const output = '\'{ "value": { "message": "job failed by timeout in active state" } }\'::jsonb'
|
|
503
501
|
return failJobs(schema, where, output)
|
|
504
502
|
}
|
|
@@ -508,36 +506,36 @@ function failJobs (schema, where, output) {
|
|
|
508
506
|
WITH results AS (
|
|
509
507
|
UPDATE ${schema}.job SET
|
|
510
508
|
state = CASE
|
|
511
|
-
WHEN
|
|
509
|
+
WHEN retry_count < retry_limit THEN '${states.retry}'::${schema}.job_state
|
|
512
510
|
ELSE '${states.failed}'::${schema}.job_state
|
|
513
511
|
END,
|
|
514
|
-
|
|
515
|
-
WHEN
|
|
512
|
+
completed_on = CASE
|
|
513
|
+
WHEN retry_count < retry_limit THEN NULL
|
|
516
514
|
ELSE now()
|
|
517
515
|
END,
|
|
518
|
-
|
|
519
|
-
WHEN
|
|
520
|
-
WHEN NOT
|
|
516
|
+
start_after = CASE
|
|
517
|
+
WHEN retry_count = retry_limit THEN start_after
|
|
518
|
+
WHEN NOT retry_backoff THEN now() + retry_delay * interval '1'
|
|
521
519
|
ELSE now() + (
|
|
522
|
-
|
|
523
|
-
|
|
520
|
+
retry_delay * 2 ^ LEAST(16, retry_count + 1) / 2 +
|
|
521
|
+
retry_delay * 2 ^ LEAST(16, retry_count + 1) / 2 * random()
|
|
524
522
|
) * interval '1'
|
|
525
523
|
END,
|
|
526
524
|
output = ${output}
|
|
527
525
|
WHERE ${where}
|
|
528
526
|
RETURNING *
|
|
529
527
|
), dlq_jobs as (
|
|
530
|
-
INSERT INTO ${schema}.job (name, data, output,
|
|
528
|
+
INSERT INTO ${schema}.job (name, data, output, retry_limit, keep_until)
|
|
531
529
|
SELECT
|
|
532
|
-
|
|
530
|
+
dead_letter,
|
|
533
531
|
data,
|
|
534
532
|
output,
|
|
535
|
-
|
|
536
|
-
|
|
533
|
+
retry_limit,
|
|
534
|
+
keep_until + (keep_until - start_after)
|
|
537
535
|
FROM results
|
|
538
536
|
WHERE state = '${states.failed}'
|
|
539
|
-
AND
|
|
540
|
-
AND NOT name =
|
|
537
|
+
AND dead_letter IS NOT NULL
|
|
538
|
+
AND NOT name = dead_letter
|
|
541
539
|
)
|
|
542
540
|
SELECT COUNT(*) FROM results
|
|
543
541
|
`
|
|
@@ -547,7 +545,7 @@ function cancelJobs (schema) {
|
|
|
547
545
|
return `
|
|
548
546
|
with results as (
|
|
549
547
|
UPDATE ${schema}.job
|
|
550
|
-
SET
|
|
548
|
+
SET completed_on = now(),
|
|
551
549
|
state = '${states.cancelled}'
|
|
552
550
|
WHERE name = $1
|
|
553
551
|
AND id IN (SELECT UNNEST($2::uuid[]))
|
|
@@ -562,7 +560,7 @@ function resumeJobs (schema) {
|
|
|
562
560
|
return `
|
|
563
561
|
with results as (
|
|
564
562
|
UPDATE ${schema}.job
|
|
565
|
-
SET
|
|
563
|
+
SET completed_on = NULL,
|
|
566
564
|
state = '${states.created}'
|
|
567
565
|
WHERE name = $1
|
|
568
566
|
AND id IN (SELECT UNNEST($2::uuid[]))
|
|
@@ -579,15 +577,15 @@ function insertJob (schema) {
|
|
|
579
577
|
name,
|
|
580
578
|
data,
|
|
581
579
|
priority,
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
580
|
+
start_after,
|
|
581
|
+
singleton_key,
|
|
582
|
+
singleton_on,
|
|
583
|
+
dead_letter,
|
|
584
|
+
expire_in,
|
|
585
|
+
keep_until,
|
|
586
|
+
retry_limit,
|
|
587
|
+
retry_delay,
|
|
588
|
+
retry_backoff,
|
|
591
589
|
policy
|
|
592
590
|
)
|
|
593
591
|
SELECT
|
|
@@ -595,27 +593,27 @@ function insertJob (schema) {
|
|
|
595
593
|
j.name,
|
|
596
594
|
data,
|
|
597
595
|
priority,
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
COALESCE(
|
|
596
|
+
start_after,
|
|
597
|
+
singleton_key,
|
|
598
|
+
singleton_on,
|
|
599
|
+
COALESCE(j.dead_letter, q.dead_letter) as dead_letter,
|
|
602
600
|
CASE
|
|
603
|
-
WHEN
|
|
601
|
+
WHEN expire_in IS NOT NULL THEN CAST(expire_in as interval)
|
|
604
602
|
WHEN q.expire_seconds IS NOT NULL THEN q.expire_seconds * interval '1s'
|
|
605
|
-
WHEN
|
|
603
|
+
WHEN expire_in_default IS NOT NULL THEN CAST(expire_in_default as interval)
|
|
606
604
|
ELSE interval '15 minutes'
|
|
607
|
-
END as
|
|
605
|
+
END as expire_in,
|
|
608
606
|
CASE
|
|
609
|
-
WHEN right(
|
|
610
|
-
ELSE
|
|
611
|
-
END as
|
|
612
|
-
COALESCE(
|
|
607
|
+
WHEN right(keep_until, 1) = 'Z' THEN CAST(keep_until as timestamp with time zone)
|
|
608
|
+
ELSE start_after + CAST(COALESCE(keep_until, (q.retention_minutes * 60)::text, keep_until_default, '14 days') as interval)
|
|
609
|
+
END as keep_until,
|
|
610
|
+
COALESCE(j.retry_limit, q.retry_limit, retry_limit_default, 2) as retry_limit,
|
|
613
611
|
CASE
|
|
614
|
-
WHEN COALESCE(
|
|
615
|
-
THEN GREATEST(COALESCE(
|
|
616
|
-
ELSE COALESCE(
|
|
617
|
-
END as
|
|
618
|
-
COALESCE(
|
|
612
|
+
WHEN COALESCE(j.retry_backoff, q.retry_backoff, retry_backoff_default, false)
|
|
613
|
+
THEN GREATEST(COALESCE(j.retry_delay, q.retry_delay, retry_delay_default), 1)
|
|
614
|
+
ELSE COALESCE(j.retry_delay, q.retry_delay, retry_delay_default, 0)
|
|
615
|
+
END as retry_delay,
|
|
616
|
+
COALESCE(j.retry_backoff, q.retry_backoff, retry_backoff_default, false) as retry_backoff,
|
|
619
617
|
q.policy
|
|
620
618
|
FROM
|
|
621
619
|
( SELECT
|
|
@@ -626,23 +624,23 @@ function insertJob (schema) {
|
|
|
626
624
|
CASE
|
|
627
625
|
WHEN right($5, 1) = 'Z' THEN CAST($5 as timestamp with time zone)
|
|
628
626
|
ELSE now() + CAST(COALESCE($5,'0') as interval)
|
|
629
|
-
END as
|
|
630
|
-
$6 as
|
|
627
|
+
END as start_after,
|
|
628
|
+
$6 as singleton_key,
|
|
631
629
|
CASE
|
|
632
630
|
WHEN $7::integer IS NOT NULL THEN 'epoch'::timestamp + '1 second'::interval * ($7 * floor((date_part('epoch', now()) + $8) / $7))
|
|
633
631
|
ELSE NULL
|
|
634
|
-
END as
|
|
635
|
-
$9 as
|
|
636
|
-
$10 as
|
|
637
|
-
$11 as
|
|
638
|
-
$12 as
|
|
639
|
-
$13 as
|
|
640
|
-
$14::int as
|
|
641
|
-
$15::int as
|
|
642
|
-
$16::int as
|
|
643
|
-
$17::int as
|
|
644
|
-
$18::bool as
|
|
645
|
-
$19::bool as
|
|
632
|
+
END as singleton_on,
|
|
633
|
+
$9 as dead_letter,
|
|
634
|
+
$10 as expire_in,
|
|
635
|
+
$11 as expire_in_default,
|
|
636
|
+
$12 as keep_until,
|
|
637
|
+
$13 as keep_until_default,
|
|
638
|
+
$14::int as retry_limit,
|
|
639
|
+
$15::int as retry_limit_default,
|
|
640
|
+
$16::int as retry_delay,
|
|
641
|
+
$17::int as retry_delay_default,
|
|
642
|
+
$18::bool as retry_backoff,
|
|
643
|
+
$19::bool as retry_backoff_default
|
|
646
644
|
) j LEFT JOIN ${schema}.queue q ON j.name = q.name
|
|
647
645
|
ON CONFLICT DO NOTHING
|
|
648
646
|
RETURNING id
|
|
@@ -653,25 +651,25 @@ function insertJobs (schema) {
|
|
|
653
651
|
return `
|
|
654
652
|
WITH defaults as (
|
|
655
653
|
SELECT
|
|
656
|
-
$2 as
|
|
657
|
-
$3 as
|
|
658
|
-
$4::int as
|
|
659
|
-
$5::int as
|
|
660
|
-
$6::bool as
|
|
654
|
+
$2 as expire_in,
|
|
655
|
+
$3 as keep_until,
|
|
656
|
+
$4::int as retry_limit,
|
|
657
|
+
$5::int as retry_delay,
|
|
658
|
+
$6::bool as retry_backoff
|
|
661
659
|
)
|
|
662
660
|
INSERT INTO ${schema}.job (
|
|
663
661
|
id,
|
|
664
662
|
name,
|
|
665
663
|
data,
|
|
666
664
|
priority,
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
665
|
+
start_after,
|
|
666
|
+
singleton_key,
|
|
667
|
+
dead_letter,
|
|
668
|
+
expire_in,
|
|
669
|
+
keep_until,
|
|
670
|
+
retry_limit,
|
|
671
|
+
retry_delay,
|
|
672
|
+
retry_backoff,
|
|
675
673
|
policy
|
|
676
674
|
)
|
|
677
675
|
SELECT
|
|
@@ -685,20 +683,20 @@ function insertJobs (schema) {
|
|
|
685
683
|
CASE
|
|
686
684
|
WHEN "expireInSeconds" IS NOT NULL THEN "expireInSeconds" * interval '1s'
|
|
687
685
|
WHEN q.expire_seconds IS NOT NULL THEN q.expire_seconds * interval '1s'
|
|
688
|
-
WHEN defaults.
|
|
686
|
+
WHEN defaults.expire_in IS NOT NULL THEN CAST(defaults.expire_in as interval)
|
|
689
687
|
ELSE interval '15 minutes'
|
|
690
|
-
END as
|
|
688
|
+
END as expire_in,
|
|
691
689
|
CASE
|
|
692
690
|
WHEN "keepUntil" IS NOT NULL THEN "keepUntil"
|
|
693
|
-
ELSE COALESCE("startAfter", now()) + CAST(COALESCE((q.retention_minutes * 60)::text, defaults.
|
|
694
|
-
END as
|
|
695
|
-
COALESCE("retryLimit", q.retry_limit, defaults.
|
|
691
|
+
ELSE COALESCE("startAfter", now()) + CAST(COALESCE((q.retention_minutes * 60)::text, defaults.keep_until, '14 days') as interval)
|
|
692
|
+
END as keep_until,
|
|
693
|
+
COALESCE("retryLimit", q.retry_limit, defaults.retry_limit, 2),
|
|
696
694
|
CASE
|
|
697
|
-
WHEN COALESCE("retryBackoff", q.retry_backoff, defaults.
|
|
698
|
-
THEN GREATEST(COALESCE("retryDelay", q.retry_delay, defaults.
|
|
699
|
-
ELSE COALESCE("retryDelay", q.retry_delay, defaults.
|
|
700
|
-
END as
|
|
701
|
-
COALESCE("retryBackoff", q.retry_backoff, defaults.
|
|
695
|
+
WHEN COALESCE("retryBackoff", q.retry_backoff, defaults.retry_backoff, false)
|
|
696
|
+
THEN GREATEST(COALESCE("retryDelay", q.retry_delay, defaults.retry_delay), 1)
|
|
697
|
+
ELSE COALESCE("retryDelay", q.retry_delay, defaults.retry_delay, 0)
|
|
698
|
+
END as retry_delay,
|
|
699
|
+
COALESCE("retryBackoff", q.retry_backoff, defaults.retry_backoff, false) as retry_backoff,
|
|
702
700
|
q.policy
|
|
703
701
|
FROM json_to_recordset($1) as j (
|
|
704
702
|
id uuid,
|
|
@@ -723,24 +721,23 @@ function insertJobs (schema) {
|
|
|
723
721
|
function drop (schema, interval) {
|
|
724
722
|
return `
|
|
725
723
|
DELETE FROM ${schema}.archive
|
|
726
|
-
WHERE
|
|
724
|
+
WHERE archived_on < (now() - interval '${interval}')
|
|
727
725
|
`
|
|
728
726
|
}
|
|
729
727
|
|
|
730
728
|
function archive (schema, completedInterval, failedInterval = completedInterval) {
|
|
729
|
+
const columns = 'id, name, priority, data, state, retry_limit, retry_count, retry_delay, retry_backoff, start_after, started_on, singleton_key, singleton_on, expire_in, created_on, completed_on, keep_until, dead_letter, policy, output'
|
|
730
|
+
|
|
731
731
|
return `
|
|
732
732
|
WITH archived_rows AS (
|
|
733
733
|
DELETE FROM ${schema}.job
|
|
734
|
-
WHERE (state <> '${states.failed}' AND
|
|
735
|
-
OR (state = '${states.failed}' AND
|
|
736
|
-
OR (state < '${states.active}' AND
|
|
734
|
+
WHERE (state <> '${states.failed}' AND completed_on < (now() - interval '${completedInterval}'))
|
|
735
|
+
OR (state = '${states.failed}' AND completed_on < (now() - interval '${failedInterval}'))
|
|
736
|
+
OR (state < '${states.active}' AND keep_until < now())
|
|
737
737
|
RETURNING *
|
|
738
738
|
)
|
|
739
|
-
INSERT INTO ${schema}.archive (
|
|
740
|
-
|
|
741
|
-
)
|
|
742
|
-
SELECT
|
|
743
|
-
id, name, priority, data, state, retryLimit, retryCount, retryDelay, retryBackoff, startAfter, startedOn, singletonKey, singletonOn, expireIn, createdOn, completedOn, keepUntil, deadletter, policy, output
|
|
739
|
+
INSERT INTO ${schema}.archive (${columns})
|
|
740
|
+
SELECT ${columns}
|
|
744
741
|
FROM archived_rows
|
|
745
742
|
`
|
|
746
743
|
}
|
|
@@ -761,6 +758,7 @@ function locked (schema, query) {
|
|
|
761
758
|
return `
|
|
762
759
|
BEGIN;
|
|
763
760
|
SET LOCAL lock_timeout = '30s';
|
|
761
|
+
SET LOCAL idle_in_transaction_session_timeout = '30s';
|
|
764
762
|
${advisoryLock(schema)};
|
|
765
763
|
${query};
|
|
766
764
|
COMMIT;
|
|
@@ -779,13 +777,13 @@ function assertMigration (schema, version) {
|
|
|
779
777
|
}
|
|
780
778
|
|
|
781
779
|
function getJobById (schema) {
|
|
782
|
-
return
|
|
780
|
+
return getJobByTableQueueId(schema, 'job')
|
|
783
781
|
}
|
|
784
782
|
|
|
785
783
|
function getArchivedJobById (schema) {
|
|
786
|
-
return
|
|
784
|
+
return getJobByTableQueueId(schema, 'archive')
|
|
787
785
|
}
|
|
788
786
|
|
|
789
|
-
function
|
|
790
|
-
return `SELECT
|
|
787
|
+
function getJobByTableQueueId (schema, table) {
|
|
788
|
+
return `SELECT ${allJobColumns} FROM ${schema}.${table} WHERE name = $1 AND id = $2`
|
|
791
789
|
}
|
package/src/timekeeper.js
CHANGED
|
@@ -31,8 +31,7 @@ class Timekeeper extends EventEmitter {
|
|
|
31
31
|
this.getSchedulesCommand = plans.getSchedules(config.schema)
|
|
32
32
|
this.scheduleCommand = plans.schedule(config.schema)
|
|
33
33
|
this.unscheduleCommand = plans.unschedule(config.schema)
|
|
34
|
-
this.
|
|
35
|
-
this.setCronTimeCommand = plans.setCronTime(config.schema)
|
|
34
|
+
this.trySetCronTimeCommand = plans.trySetCronTime(config.schema)
|
|
36
35
|
|
|
37
36
|
this.functions = [
|
|
38
37
|
this.schedule,
|
|
@@ -44,27 +43,30 @@ class Timekeeper extends EventEmitter {
|
|
|
44
43
|
}
|
|
45
44
|
|
|
46
45
|
async start () {
|
|
47
|
-
this.stopped = false
|
|
48
|
-
|
|
49
46
|
// setting the archive config too low breaks the cron 60s debounce interval so don't even try
|
|
50
47
|
if (this.config.archiveSeconds < 60 || this.config.archiveFailedSeconds < 60) {
|
|
51
48
|
return
|
|
52
49
|
}
|
|
53
50
|
|
|
54
|
-
|
|
51
|
+
this.stopped = false
|
|
52
|
+
|
|
55
53
|
await this.cacheClockSkew()
|
|
56
54
|
|
|
57
55
|
try {
|
|
58
56
|
await this.manager.createQueue(queues.SEND_IT)
|
|
59
57
|
} catch {}
|
|
60
58
|
|
|
61
|
-
|
|
59
|
+
const options = {
|
|
60
|
+
newJobCheckIntervalSeconds: this.config.cronWorkerIntervalSeconds,
|
|
61
|
+
teamSize: 50,
|
|
62
|
+
teamConcurrency: 5
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
await this.manager.work(queues.SEND_IT, options, (job) => this.onSendIt(job))
|
|
62
66
|
|
|
63
67
|
setImmediate(() => this.onCron())
|
|
64
68
|
|
|
65
|
-
// create monitoring interval to make sure cron hasn't crashed
|
|
66
69
|
this.cronMonitorInterval = setInterval(async () => await this.onCron(), this.cronMonitorIntervalMs)
|
|
67
|
-
// create monitoring interval to measure and adjust for drift in clock skew
|
|
68
70
|
this.skewMonitorInterval = setInterval(async () => await this.cacheClockSkew(), this.skewMonitorIntervalMs)
|
|
69
71
|
}
|
|
70
72
|
|
|
@@ -117,8 +119,6 @@ class Timekeeper extends EventEmitter {
|
|
|
117
119
|
}
|
|
118
120
|
|
|
119
121
|
async onCron () {
|
|
120
|
-
let locker
|
|
121
|
-
|
|
122
122
|
try {
|
|
123
123
|
if (this.stopped || this.timekeeping) return
|
|
124
124
|
|
|
@@ -128,19 +128,15 @@ class Timekeeper extends EventEmitter {
|
|
|
128
128
|
|
|
129
129
|
this.timekeeping = true
|
|
130
130
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
const { secondsAgo } = await this.getCronTime()
|
|
131
|
+
const { rows } = await this.db.executeSql(this.trySetCronTimeCommand, [this.config.cronMonitorIntervalSeconds])
|
|
134
132
|
|
|
135
|
-
if (
|
|
133
|
+
if (rows.length === 1 && !this.stopped) {
|
|
136
134
|
await this.cron()
|
|
137
|
-
await this.setCronTime()
|
|
138
135
|
}
|
|
139
136
|
} catch (err) {
|
|
140
137
|
this.emit(this.events.error, err)
|
|
141
138
|
} finally {
|
|
142
139
|
this.timekeeping = false
|
|
143
|
-
await locker?.unlock()
|
|
144
140
|
}
|
|
145
141
|
}
|
|
146
142
|
|
|
@@ -198,28 +194,11 @@ class Timekeeper extends EventEmitter {
|
|
|
198
194
|
|
|
199
195
|
const values = [name, cron, tz, data, options]
|
|
200
196
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
return result ? result.rowCount : null
|
|
197
|
+
await this.db.executeSql(this.scheduleCommand, values)
|
|
204
198
|
}
|
|
205
199
|
|
|
206
200
|
async unschedule (name) {
|
|
207
|
-
|
|
208
|
-
return result ? result.rowCount : null
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
async setCronTime () {
|
|
212
|
-
await this.db.executeSql(this.setCronTimeCommand)
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
async getCronTime () {
|
|
216
|
-
const { rows } = await this.db.executeSql(this.getCronTimeCommand)
|
|
217
|
-
|
|
218
|
-
let { cron_on: cronOn, seconds_ago: secondsAgo } = rows[0]
|
|
219
|
-
|
|
220
|
-
secondsAgo = secondsAgo !== null ? parseFloat(secondsAgo) : 61
|
|
221
|
-
|
|
222
|
-
return { cronOn, secondsAgo }
|
|
201
|
+
await this.db.executeSql(this.unscheduleCommand, [name])
|
|
223
202
|
}
|
|
224
203
|
}
|
|
225
204
|
|
package/types.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { EventEmitter } from 'events'
|
|
|
2
2
|
|
|
3
3
|
declare namespace PgBoss {
|
|
4
4
|
interface Db {
|
|
5
|
-
executeSql(text: string, values: any[]): Promise<{ rows: any[]
|
|
5
|
+
executeSql(text: string, values: any[]): Promise<{ rows: any[] }>;
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
interface DatabaseOptions {
|
|
@@ -91,10 +91,14 @@ declare namespace PgBoss {
|
|
|
91
91
|
interface ConnectionOptions {
|
|
92
92
|
db?: Db;
|
|
93
93
|
}
|
|
94
|
-
|
|
94
|
+
|
|
95
95
|
type InsertOptions = ConnectionOptions;
|
|
96
|
-
|
|
96
|
+
|
|
97
97
|
type SendOptions = JobOptions & ExpirationOptions & RetentionOptions & RetryOptions & ConnectionOptions;
|
|
98
|
+
|
|
99
|
+
type QueuePolicy = 'standard' | 'short' | 'singleton' | 'stately'
|
|
100
|
+
type Queue = ExpirationOptions & RetentionOptions & RetryOptions & { policy: QueuePolicy }
|
|
101
|
+
type QueueUpdateOptions = ExpirationOptions & RetentionOptions & RetryOptions
|
|
98
102
|
|
|
99
103
|
type ScheduleOptions = SendOptions & { tz?: string }
|
|
100
104
|
|
|
@@ -176,24 +180,26 @@ declare namespace PgBoss {
|
|
|
176
180
|
data: T;
|
|
177
181
|
}
|
|
178
182
|
|
|
179
|
-
interface JobWithMetadata<T = object>
|
|
183
|
+
interface JobWithMetadata<T = object> {
|
|
184
|
+
id: string;
|
|
185
|
+
name: string;
|
|
186
|
+
data: T;
|
|
180
187
|
priority: number;
|
|
181
188
|
state: 'created' | 'retry' | 'active' | 'completed' | 'cancelled' | 'failed';
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
deadletter: string,
|
|
189
|
+
retryLimit: number;
|
|
190
|
+
retryCount: number;
|
|
191
|
+
retryDelay: number;
|
|
192
|
+
retryBackoff: boolean;
|
|
193
|
+
startAfter: Date;
|
|
194
|
+
startedOn: Date;
|
|
195
|
+
singletonKey: string | null;
|
|
196
|
+
singletonOn: Date | null;
|
|
197
|
+
expireIn: PostgresInterval;
|
|
198
|
+
createdOn: Date;
|
|
199
|
+
completedOn: Date | null;
|
|
200
|
+
keepUntil: Date;
|
|
201
|
+
deadLetter: string,
|
|
202
|
+
policy: QueuePolicy,
|
|
197
203
|
output: object
|
|
198
204
|
}
|
|
199
205
|
|
|
@@ -314,10 +320,6 @@ declare class PgBoss extends EventEmitter {
|
|
|
314
320
|
offWork(name: string): Promise<void>;
|
|
315
321
|
offWork(options: PgBoss.OffWorkOptions): Promise<void>;
|
|
316
322
|
|
|
317
|
-
/**
|
|
318
|
-
* Notify worker that something has changed
|
|
319
|
-
* @param workerId
|
|
320
|
-
*/
|
|
321
323
|
notifyWorker(workerId: string): void;
|
|
322
324
|
|
|
323
325
|
subscribe(event: string, name: string): Promise<void>;
|
|
@@ -348,15 +350,19 @@ declare class PgBoss extends EventEmitter {
|
|
|
348
350
|
getQueueSize(name: string, options?: object): Promise<number>;
|
|
349
351
|
getJobById(name: string, id: string, options?: PgBoss.ConnectionOptions): Promise<PgBoss.JobWithMetadata | null>;
|
|
350
352
|
|
|
351
|
-
createQueue(name: string, options?:
|
|
353
|
+
createQueue(name: string, options?: PgBoss.Queue): Promise<void>;
|
|
354
|
+
getQueue(name: string): Promise<PgBoss.Queue | null>;
|
|
355
|
+
updateQueue(name: string, options?: PgBoss.QueueUpdateOptions): Promise<void>;
|
|
352
356
|
deleteQueue(name: string): Promise<void>;
|
|
353
357
|
purgeQueue(name: string): Promise<void>;
|
|
354
|
-
clearStorage(): Promise<void>;
|
|
355
358
|
|
|
359
|
+
clearStorage(): Promise<void>;
|
|
356
360
|
archive(): Promise<void>;
|
|
357
361
|
purge(): Promise<void>;
|
|
358
362
|
expire(): Promise<void>;
|
|
359
363
|
maintain(): Promise<void>;
|
|
364
|
+
isInstalled(): Promise<Boolean>;
|
|
365
|
+
schemaVersion(): Promise<Number>;
|
|
360
366
|
|
|
361
367
|
schedule(name: string, cron: string, data?: object, options?: PgBoss.ScheduleOptions): Promise<void>;
|
|
362
368
|
unschedule(name: string): Promise<void>;
|