pg-boss 10.0.0-beta2 → 10.0.0-beta21
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 +17 -20
- package/package.json +1 -3
- package/src/attorney.js +35 -36
- package/src/boss.js +13 -57
- package/src/contractor.js +18 -12
- package/src/db.js +12 -38
- package/src/index.js +92 -67
- package/src/manager.js +109 -164
- package/src/plans.js +404 -298
- package/src/timekeeper.js +51 -98
- package/types.d.ts +70 -67
package/src/plans.js
CHANGED
|
@@ -1,24 +1,22 @@
|
|
|
1
|
-
const
|
|
1
|
+
const DEFAULT_SCHEMA = 'pgboss'
|
|
2
|
+
const MIGRATE_RACE_MESSAGE = 'division by zero'
|
|
3
|
+
const CREATE_RACE_MESSAGE = 'already exists'
|
|
2
4
|
|
|
3
|
-
const
|
|
5
|
+
const JOB_STATES = Object.freeze({
|
|
4
6
|
created: 'created',
|
|
5
7
|
retry: 'retry',
|
|
6
8
|
active: 'active',
|
|
7
9
|
completed: 'completed',
|
|
8
10
|
cancelled: 'cancelled',
|
|
9
11
|
failed: 'failed'
|
|
10
|
-
}
|
|
12
|
+
})
|
|
11
13
|
|
|
12
|
-
const
|
|
13
|
-
const MIGRATE_RACE_MESSAGE = 'division by zero'
|
|
14
|
-
const CREATE_RACE_MESSAGE = 'already exists'
|
|
15
|
-
|
|
16
|
-
const QUEUE_POLICY = {
|
|
14
|
+
const QUEUE_POLICIES = Object.freeze({
|
|
17
15
|
standard: 'standard',
|
|
18
16
|
short: 'short',
|
|
19
17
|
singleton: 'singleton',
|
|
20
18
|
stately: 'stately'
|
|
21
|
-
}
|
|
19
|
+
})
|
|
22
20
|
|
|
23
21
|
module.exports = {
|
|
24
22
|
create,
|
|
@@ -30,6 +28,7 @@ module.exports = {
|
|
|
30
28
|
completeJobs,
|
|
31
29
|
cancelJobs,
|
|
32
30
|
resumeJobs,
|
|
31
|
+
deleteJobs,
|
|
33
32
|
failJobsById,
|
|
34
33
|
failJobsByTimeout,
|
|
35
34
|
insertJob,
|
|
@@ -44,57 +43,49 @@ module.exports = {
|
|
|
44
43
|
archive,
|
|
45
44
|
drop,
|
|
46
45
|
countStates,
|
|
47
|
-
createQueue,
|
|
48
46
|
updateQueue,
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
47
|
+
createQueue,
|
|
48
|
+
deleteQueue,
|
|
49
|
+
getQueues,
|
|
52
50
|
getQueueByName,
|
|
53
51
|
getQueueSize,
|
|
54
52
|
purgeQueue,
|
|
55
53
|
clearStorage,
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
setMonitorTime,
|
|
60
|
-
getCronTime,
|
|
61
|
-
setCronTime,
|
|
54
|
+
trySetMaintenanceTime,
|
|
55
|
+
trySetMonitorTime,
|
|
56
|
+
trySetCronTime,
|
|
62
57
|
locked,
|
|
63
|
-
advisoryLock,
|
|
64
58
|
assertMigration,
|
|
65
59
|
getArchivedJobById,
|
|
66
60
|
getJobById,
|
|
67
|
-
|
|
68
|
-
|
|
61
|
+
QUEUE_POLICIES,
|
|
62
|
+
JOB_STATES,
|
|
69
63
|
MIGRATE_RACE_MESSAGE,
|
|
70
64
|
CREATE_RACE_MESSAGE,
|
|
71
65
|
DEFAULT_SCHEMA
|
|
72
66
|
}
|
|
73
67
|
|
|
68
|
+
const assert = require('assert')
|
|
69
|
+
|
|
74
70
|
function create (schema, version) {
|
|
75
71
|
const commands = [
|
|
76
72
|
createSchema(schema),
|
|
77
73
|
createEnumJobState(schema),
|
|
78
74
|
|
|
75
|
+
createTableVersion(schema),
|
|
76
|
+
createTableQueue(schema),
|
|
77
|
+
createTableSchedule(schema),
|
|
78
|
+
createTableSubscription(schema),
|
|
79
|
+
|
|
79
80
|
createTableJob(schema),
|
|
80
|
-
createIndexJobName(schema),
|
|
81
|
-
createIndexJobFetch(schema),
|
|
82
|
-
createIndexJobPolicyStately(schema),
|
|
83
|
-
createIndexJobPolicyShort(schema),
|
|
84
|
-
createIndexJobPolicySingleton(schema),
|
|
85
|
-
createIndexJobThrottleOn(schema),
|
|
86
|
-
createIndexJobThrottleKey(schema),
|
|
87
81
|
|
|
88
82
|
createTableArchive(schema),
|
|
89
83
|
createPrimaryKeyArchive(schema),
|
|
90
84
|
createColumnArchiveArchivedOn(schema),
|
|
91
85
|
createIndexArchiveArchivedOn(schema),
|
|
92
|
-
createIndexArchiveName(schema),
|
|
93
86
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
createTableSchedule(schema),
|
|
97
|
-
createTableSubscription(schema),
|
|
87
|
+
createQueueFunction(schema),
|
|
88
|
+
deleteQueueFunction(schema),
|
|
98
89
|
|
|
99
90
|
insertVersion(schema, version)
|
|
100
91
|
]
|
|
@@ -108,6 +99,21 @@ function createSchema (schema) {
|
|
|
108
99
|
`
|
|
109
100
|
}
|
|
110
101
|
|
|
102
|
+
function createEnumJobState (schema) {
|
|
103
|
+
// ENUM definition order is important
|
|
104
|
+
// base type is numeric and first values are less than last values
|
|
105
|
+
return `
|
|
106
|
+
CREATE TYPE ${schema}.job_state AS ENUM (
|
|
107
|
+
'${JOB_STATES.created}',
|
|
108
|
+
'${JOB_STATES.retry}',
|
|
109
|
+
'${JOB_STATES.active}',
|
|
110
|
+
'${JOB_STATES.completed}',
|
|
111
|
+
'${JOB_STATES.cancelled}',
|
|
112
|
+
'${JOB_STATES.failed}'
|
|
113
|
+
)
|
|
114
|
+
`
|
|
115
|
+
}
|
|
116
|
+
|
|
111
117
|
function createTableVersion (schema) {
|
|
112
118
|
return `
|
|
113
119
|
CREATE TABLE ${schema}.version (
|
|
@@ -119,17 +125,48 @@ function createTableVersion (schema) {
|
|
|
119
125
|
`
|
|
120
126
|
}
|
|
121
127
|
|
|
122
|
-
function
|
|
123
|
-
// ENUM definition order is important
|
|
124
|
-
// base type is numeric and first values are less than last values
|
|
128
|
+
function createTableQueue (schema) {
|
|
125
129
|
return `
|
|
126
|
-
CREATE
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
130
|
+
CREATE TABLE ${schema}.queue (
|
|
131
|
+
name text,
|
|
132
|
+
policy text,
|
|
133
|
+
retry_limit int,
|
|
134
|
+
retry_delay int,
|
|
135
|
+
retry_backoff bool,
|
|
136
|
+
expire_seconds int,
|
|
137
|
+
retention_minutes int,
|
|
138
|
+
dead_letter text REFERENCES ${schema}.queue (name),
|
|
139
|
+
partition_name text,
|
|
140
|
+
created_on timestamp with time zone not null default now(),
|
|
141
|
+
updated_on timestamp with time zone not null default now(),
|
|
142
|
+
PRIMARY KEY (name)
|
|
143
|
+
)
|
|
144
|
+
`
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function createTableSchedule (schema) {
|
|
148
|
+
return `
|
|
149
|
+
CREATE TABLE ${schema}.schedule (
|
|
150
|
+
name text REFERENCES ${schema}.queue ON DELETE CASCADE,
|
|
151
|
+
cron text not null,
|
|
152
|
+
timezone text,
|
|
153
|
+
data jsonb,
|
|
154
|
+
options jsonb,
|
|
155
|
+
created_on timestamp with time zone not null default now(),
|
|
156
|
+
updated_on timestamp with time zone not null default now(),
|
|
157
|
+
PRIMARY KEY (name)
|
|
158
|
+
)
|
|
159
|
+
`
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function createTableSubscription (schema) {
|
|
163
|
+
return `
|
|
164
|
+
CREATE TABLE ${schema}.subscription (
|
|
165
|
+
event text not null,
|
|
166
|
+
name text not null REFERENCES ${schema}.queue ON DELETE CASCADE,
|
|
167
|
+
created_on timestamp with time zone not null default now(),
|
|
168
|
+
updated_on timestamp with time zone not null default now(),
|
|
169
|
+
PRIMARY KEY(event, name)
|
|
133
170
|
)
|
|
134
171
|
`
|
|
135
172
|
}
|
|
@@ -141,146 +178,238 @@ function createTableJob (schema) {
|
|
|
141
178
|
name text not null,
|
|
142
179
|
priority integer not null default(0),
|
|
143
180
|
data jsonb,
|
|
144
|
-
state ${schema}.job_state not null default('${
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
181
|
+
state ${schema}.job_state not null default('${JOB_STATES.created}'),
|
|
182
|
+
retry_limit integer not null default(0),
|
|
183
|
+
retry_count integer not null default(0),
|
|
184
|
+
retry_delay integer not null default(0),
|
|
185
|
+
retry_backoff boolean not null default false,
|
|
186
|
+
start_after timestamp with time zone not null default now(),
|
|
187
|
+
started_on timestamp with time zone,
|
|
188
|
+
singleton_key text,
|
|
189
|
+
singleton_on timestamp without time zone,
|
|
190
|
+
expire_in interval not null default interval '15 minutes',
|
|
191
|
+
created_on timestamp with time zone not null default now(),
|
|
192
|
+
completed_on timestamp with time zone,
|
|
193
|
+
keep_until timestamp with time zone NOT NULL default now() + interval '14 days',
|
|
157
194
|
output jsonb,
|
|
158
|
-
|
|
159
|
-
policy text
|
|
160
|
-
CONSTRAINT job_pkey PRIMARY KEY (name, id)
|
|
195
|
+
dead_letter text,
|
|
196
|
+
policy text
|
|
161
197
|
) PARTITION BY LIST (name)
|
|
162
198
|
`
|
|
163
199
|
}
|
|
164
200
|
|
|
165
|
-
|
|
201
|
+
const baseJobColumns = 'id, name, data, EXTRACT(epoch FROM expire_in) as "expireInSeconds"'
|
|
202
|
+
const allJobColumns = `${baseJobColumns},
|
|
203
|
+
policy,
|
|
204
|
+
state,
|
|
205
|
+
priority,
|
|
206
|
+
retry_limit as "retryLimit",
|
|
207
|
+
retry_count as "retryCount",
|
|
208
|
+
retry_delay as "retryDelay",
|
|
209
|
+
retry_backoff as "retryBackoff",
|
|
210
|
+
start_after as "startAfter",
|
|
211
|
+
started_on as "startedOn",
|
|
212
|
+
singleton_key as "singletonKey",
|
|
213
|
+
singleton_on as "singletonOn",
|
|
214
|
+
expire_in as "expireIn",
|
|
215
|
+
created_on as "createdOn",
|
|
216
|
+
completed_on as "completedOn",
|
|
217
|
+
keep_until as "keepUntil",
|
|
218
|
+
dead_letter as "deadLetter",
|
|
219
|
+
output
|
|
220
|
+
`
|
|
221
|
+
|
|
222
|
+
function createQueueFunction (schema) {
|
|
166
223
|
return `
|
|
167
|
-
CREATE
|
|
168
|
-
|
|
169
|
-
|
|
224
|
+
CREATE FUNCTION ${schema}.create_queue(queue_name text, options json)
|
|
225
|
+
RETURNS VOID AS
|
|
226
|
+
$$
|
|
227
|
+
DECLARE
|
|
228
|
+
table_name varchar := 'j' || encode(sha224(queue_name::bytea), 'hex');
|
|
229
|
+
BEGIN
|
|
230
|
+
|
|
231
|
+
INSERT INTO ${schema}.queue (
|
|
232
|
+
name,
|
|
233
|
+
policy,
|
|
234
|
+
retry_limit,
|
|
235
|
+
retry_delay,
|
|
236
|
+
retry_backoff,
|
|
237
|
+
expire_seconds,
|
|
238
|
+
retention_minutes,
|
|
239
|
+
dead_letter,
|
|
240
|
+
partition_name
|
|
241
|
+
)
|
|
242
|
+
VALUES (
|
|
243
|
+
queue_name,
|
|
244
|
+
options->>'policy',
|
|
245
|
+
(options->>'retryLimit')::int,
|
|
246
|
+
(options->>'retryDelay')::int,
|
|
247
|
+
(options->>'retryBackoff')::bool,
|
|
248
|
+
(options->>'expireInSeconds')::int,
|
|
249
|
+
(options->>'retentionMinutes')::int,
|
|
250
|
+
options->>'deadLetter',
|
|
251
|
+
table_name
|
|
252
|
+
);
|
|
253
|
+
|
|
254
|
+
EXECUTE format('CREATE TABLE ${schema}.%I (LIKE ${schema}.job INCLUDING DEFAULTS)', table_name);
|
|
255
|
+
|
|
256
|
+
EXECUTE format('${formatPartitionCommand(createPrimaryKeyJob(schema))}', table_name);
|
|
257
|
+
EXECUTE format('${formatPartitionCommand(createQueueForeignKeyJob(schema))}', table_name);
|
|
258
|
+
EXECUTE format('${formatPartitionCommand(createQueueForeignKeyJobDeadLetter(schema))}', table_name);
|
|
259
|
+
EXECUTE format('${formatPartitionCommand(createIndexJobPolicyShort(schema))}', table_name);
|
|
260
|
+
EXECUTE format('${formatPartitionCommand(createIndexJobPolicySingleton(schema))}', table_name);
|
|
261
|
+
EXECUTE format('${formatPartitionCommand(createIndexJobPolicyStately(schema))}', table_name);
|
|
262
|
+
EXECUTE format('${formatPartitionCommand(createIndexJobThrottle(schema))}', table_name);
|
|
263
|
+
EXECUTE format('${formatPartitionCommand(createIndexJobFetch(schema))}', table_name);
|
|
264
|
+
|
|
265
|
+
EXECUTE format('ALTER TABLE ${schema}.%I ADD CONSTRAINT cjc CHECK (name=%L)', table_name, queue_name);
|
|
266
|
+
EXECUTE format('ALTER TABLE ${schema}.job ATTACH PARTITION ${schema}.%I FOR VALUES IN (%L)', table_name, queue_name);
|
|
267
|
+
END;
|
|
268
|
+
$$
|
|
269
|
+
LANGUAGE plpgsql;
|
|
170
270
|
`
|
|
171
271
|
}
|
|
172
272
|
|
|
173
|
-
function
|
|
174
|
-
return
|
|
273
|
+
function formatPartitionCommand (command) {
|
|
274
|
+
return command.replace('.job', '.%1$I').replace('job_i', '%1$s_i').replaceAll('\'', '\'\'')
|
|
175
275
|
}
|
|
176
276
|
|
|
177
|
-
function
|
|
178
|
-
return `
|
|
277
|
+
function deleteQueueFunction (schema) {
|
|
278
|
+
return `
|
|
279
|
+
CREATE FUNCTION ${schema}.delete_queue(queue_name text)
|
|
280
|
+
RETURNS VOID AS
|
|
281
|
+
$$
|
|
282
|
+
DECLARE
|
|
283
|
+
table_name varchar;
|
|
284
|
+
BEGIN
|
|
285
|
+
WITH deleted as (
|
|
286
|
+
DELETE FROM ${schema}.queue
|
|
287
|
+
WHERE name = queue_name
|
|
288
|
+
RETURNING partition_name
|
|
289
|
+
)
|
|
290
|
+
SELECT partition_name from deleted INTO table_name;
|
|
291
|
+
|
|
292
|
+
EXECUTE format('DROP TABLE IF EXISTS ${schema}.%I', table_name);
|
|
293
|
+
END;
|
|
294
|
+
$$
|
|
295
|
+
LANGUAGE plpgsql;
|
|
296
|
+
`
|
|
179
297
|
}
|
|
180
298
|
|
|
181
|
-
function
|
|
182
|
-
return `
|
|
299
|
+
function createQueue (schema) {
|
|
300
|
+
return `SELECT ${schema}.create_queue($1, $2)`
|
|
183
301
|
}
|
|
184
302
|
|
|
185
|
-
function
|
|
186
|
-
return `
|
|
303
|
+
function deleteQueue (schema) {
|
|
304
|
+
return `SELECT ${schema}.delete_queue($1)`
|
|
187
305
|
}
|
|
188
306
|
|
|
189
|
-
function
|
|
190
|
-
return `
|
|
307
|
+
function createPrimaryKeyJob (schema) {
|
|
308
|
+
return `ALTER TABLE ${schema}.job ADD PRIMARY KEY (name, id)`
|
|
191
309
|
}
|
|
192
310
|
|
|
193
|
-
function
|
|
194
|
-
return `
|
|
311
|
+
function createQueueForeignKeyJob (schema) {
|
|
312
|
+
return `ALTER TABLE ${schema}.job ADD CONSTRAINT q_fkey FOREIGN KEY (name) REFERENCES ${schema}.queue (name) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED`
|
|
195
313
|
}
|
|
196
314
|
|
|
197
|
-
function
|
|
198
|
-
return `
|
|
315
|
+
function createQueueForeignKeyJobDeadLetter (schema) {
|
|
316
|
+
return `ALTER TABLE ${schema}.job ADD CONSTRAINT dlq_fkey FOREIGN KEY (dead_letter) REFERENCES ${schema}.queue (name) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED`
|
|
199
317
|
}
|
|
200
318
|
|
|
201
|
-
function
|
|
202
|
-
return `
|
|
319
|
+
function createPrimaryKeyArchive (schema) {
|
|
320
|
+
return `ALTER TABLE ${schema}.archive ADD PRIMARY KEY (name, id)`
|
|
203
321
|
}
|
|
204
322
|
|
|
205
|
-
function
|
|
206
|
-
return `CREATE INDEX
|
|
323
|
+
function createIndexJobPolicyShort (schema) {
|
|
324
|
+
return `CREATE UNIQUE INDEX job_i1 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state = '${JOB_STATES.created}' AND policy = '${QUEUE_POLICIES.short}';`
|
|
207
325
|
}
|
|
208
326
|
|
|
209
|
-
function
|
|
210
|
-
return `CREATE
|
|
327
|
+
function createIndexJobPolicySingleton (schema) {
|
|
328
|
+
return `CREATE UNIQUE INDEX job_i2 ON ${schema}.job (name, COALESCE(singleton_key, '')) WHERE state = '${JOB_STATES.active}' AND policy = '${QUEUE_POLICIES.singleton}'`
|
|
211
329
|
}
|
|
212
330
|
|
|
213
|
-
function
|
|
214
|
-
return `
|
|
331
|
+
function createIndexJobPolicyStately (schema) {
|
|
332
|
+
return `CREATE UNIQUE INDEX job_i3 ON ${schema}.job (name, state, COALESCE(singleton_key, '')) WHERE state <= '${JOB_STATES.active}' AND policy = '${QUEUE_POLICIES.stately}'`
|
|
215
333
|
}
|
|
216
334
|
|
|
217
|
-
function
|
|
218
|
-
return `CREATE INDEX
|
|
335
|
+
function createIndexJobThrottle (schema) {
|
|
336
|
+
return `CREATE UNIQUE INDEX job_i4 ON ${schema}.job (name, singleton_on, COALESCE(singleton_key, '')) WHERE state <> '${JOB_STATES.cancelled}' AND singleton_on IS NOT NULL`
|
|
219
337
|
}
|
|
220
338
|
|
|
221
|
-
function
|
|
222
|
-
return `CREATE INDEX
|
|
339
|
+
function createIndexJobFetch (schema) {
|
|
340
|
+
return `CREATE INDEX job_i5 ON ${schema}.job (name, start_after) INCLUDE (priority, created_on, id) WHERE state < '${JOB_STATES.active}'`
|
|
223
341
|
}
|
|
224
342
|
|
|
225
|
-
function
|
|
226
|
-
return `
|
|
343
|
+
function createTableArchive (schema) {
|
|
344
|
+
return `CREATE TABLE ${schema}.archive (LIKE ${schema}.job)`
|
|
227
345
|
}
|
|
228
346
|
|
|
229
|
-
function
|
|
230
|
-
return `
|
|
347
|
+
function createColumnArchiveArchivedOn (schema) {
|
|
348
|
+
return `ALTER TABLE ${schema}.archive ADD archived_on timestamptz NOT NULL DEFAULT now()`
|
|
231
349
|
}
|
|
232
350
|
|
|
233
|
-
function
|
|
234
|
-
return `
|
|
351
|
+
function createIndexArchiveArchivedOn (schema) {
|
|
352
|
+
return `CREATE INDEX archive_i1 ON ${schema}.archive(archived_on)`
|
|
235
353
|
}
|
|
236
354
|
|
|
237
|
-
function
|
|
238
|
-
return
|
|
355
|
+
function trySetMaintenanceTime (schema) {
|
|
356
|
+
return trySetTimestamp(schema, 'maintained_on')
|
|
239
357
|
}
|
|
240
358
|
|
|
241
|
-
function
|
|
242
|
-
|
|
243
|
-
return `UPDATE ${schema}.version SET cron_on = ${time}`
|
|
359
|
+
function trySetMonitorTime (schema) {
|
|
360
|
+
return trySetTimestamp(schema, 'monitored_on')
|
|
244
361
|
}
|
|
245
362
|
|
|
246
|
-
function
|
|
247
|
-
return
|
|
363
|
+
function trySetCronTime (schema) {
|
|
364
|
+
return trySetTimestamp(schema, 'cron_on')
|
|
248
365
|
}
|
|
249
366
|
|
|
250
|
-
function
|
|
367
|
+
function trySetTimestamp (schema, column) {
|
|
251
368
|
return `
|
|
252
|
-
|
|
253
|
-
|
|
369
|
+
UPDATE ${schema}.version SET ${column} = now()
|
|
370
|
+
WHERE EXTRACT( EPOCH FROM (now() - COALESCE(${column}, now() - interval '1 week') ) ) > $1
|
|
371
|
+
RETURNING true
|
|
254
372
|
`
|
|
255
373
|
}
|
|
256
374
|
|
|
257
375
|
function updateQueue (schema) {
|
|
258
376
|
return `
|
|
259
377
|
UPDATE ${schema}.queue SET
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
378
|
+
policy = COALESCE($2, policy),
|
|
379
|
+
retry_limit = COALESCE($3, retry_limit),
|
|
380
|
+
retry_delay = COALESCE($4, retry_delay),
|
|
381
|
+
retry_backoff = COALESCE($5, retry_backoff),
|
|
382
|
+
expire_seconds = COALESCE($6, expire_seconds),
|
|
383
|
+
retention_minutes = COALESCE($7, retention_minutes),
|
|
384
|
+
dead_letter = COALESCE($8, dead_letter),
|
|
385
|
+
updated_on = now()
|
|
266
386
|
WHERE name = $1
|
|
267
387
|
`
|
|
268
388
|
}
|
|
269
389
|
|
|
270
|
-
function
|
|
271
|
-
return `
|
|
390
|
+
function getQueues (schema) {
|
|
391
|
+
return `
|
|
392
|
+
SELECT
|
|
393
|
+
name,
|
|
394
|
+
policy,
|
|
395
|
+
retry_limit as "retryLimit",
|
|
396
|
+
retry_delay as "retryDelay",
|
|
397
|
+
retry_backoff as "retryBackoff",
|
|
398
|
+
expire_seconds as "expireInSeconds",
|
|
399
|
+
retention_minutes as "retentionMinutes",
|
|
400
|
+
dead_letter as "deadLetter",
|
|
401
|
+
created_on as "createdOn",
|
|
402
|
+
updated_on as "updatedOn"
|
|
403
|
+
FROM ${schema}.queue
|
|
404
|
+
`
|
|
272
405
|
}
|
|
273
406
|
|
|
274
|
-
function
|
|
275
|
-
return
|
|
276
|
-
DELETE FROM ${schema}.queue WHERE name = $1
|
|
277
|
-
)
|
|
278
|
-
DELETE FROM ${schema}.job WHERE name = $1
|
|
279
|
-
`
|
|
407
|
+
function getQueueByName (schema) {
|
|
408
|
+
return `${getQueues(schema)} WHERE name = $1`
|
|
280
409
|
}
|
|
281
410
|
|
|
282
411
|
function purgeQueue (schema) {
|
|
283
|
-
return `DELETE from ${schema}.job WHERE name = $1 and state < '${
|
|
412
|
+
return `DELETE from ${schema}.job WHERE name = $1 and state < '${JOB_STATES.active}'`
|
|
284
413
|
}
|
|
285
414
|
|
|
286
415
|
function clearStorage (schema) {
|
|
@@ -288,57 +417,13 @@ function clearStorage (schema) {
|
|
|
288
417
|
}
|
|
289
418
|
|
|
290
419
|
function getQueueSize (schema, options = {}) {
|
|
291
|
-
options.before = options.before ||
|
|
292
|
-
assert(options.before in
|
|
420
|
+
options.before = options.before || JOB_STATES.active
|
|
421
|
+
assert(options.before in JOB_STATES, `${options.before} is not a valid state`)
|
|
293
422
|
return `SELECT count(*) as count FROM ${schema}.job WHERE name = $1 AND state < '${options.before}'`
|
|
294
423
|
}
|
|
295
424
|
|
|
296
|
-
function createTableQueue (schema) {
|
|
297
|
-
return `
|
|
298
|
-
CREATE TABLE ${schema}.queue (
|
|
299
|
-
name text primary key,
|
|
300
|
-
policy text,
|
|
301
|
-
retry_limit int,
|
|
302
|
-
retry_delay int,
|
|
303
|
-
retry_backoff bool,
|
|
304
|
-
expire_seconds int,
|
|
305
|
-
retention_minutes int,
|
|
306
|
-
dead_letter text,
|
|
307
|
-
created_on timestamp with time zone not null default now()
|
|
308
|
-
)
|
|
309
|
-
`
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
function createTableSchedule (schema) {
|
|
313
|
-
return `
|
|
314
|
-
CREATE TABLE ${schema}.schedule (
|
|
315
|
-
name text primary key,
|
|
316
|
-
cron text not null,
|
|
317
|
-
timezone text,
|
|
318
|
-
data jsonb,
|
|
319
|
-
options jsonb,
|
|
320
|
-
created_on timestamp with time zone not null default now(),
|
|
321
|
-
updated_on timestamp with time zone not null default now()
|
|
322
|
-
)
|
|
323
|
-
`
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
function createTableSubscription (schema) {
|
|
327
|
-
return `
|
|
328
|
-
CREATE TABLE ${schema}.subscription (
|
|
329
|
-
event text not null,
|
|
330
|
-
name text not null,
|
|
331
|
-
created_on timestamp with time zone not null default now(),
|
|
332
|
-
updated_on timestamp with time zone not null default now(),
|
|
333
|
-
PRIMARY KEY(event, name)
|
|
334
|
-
)
|
|
335
|
-
`
|
|
336
|
-
}
|
|
337
|
-
|
|
338
425
|
function getSchedules (schema) {
|
|
339
|
-
return `
|
|
340
|
-
SELECT * FROM ${schema}.schedule
|
|
341
|
-
`
|
|
426
|
+
return `SELECT * FROM ${schema}.schedule`
|
|
342
427
|
}
|
|
343
428
|
|
|
344
429
|
function schedule (schema) {
|
|
@@ -412,20 +497,19 @@ function fetchNextJob (schema) {
|
|
|
412
497
|
SELECT id
|
|
413
498
|
FROM ${schema}.job
|
|
414
499
|
WHERE name = $1
|
|
415
|
-
AND state < '${
|
|
416
|
-
AND
|
|
417
|
-
ORDER BY ${priority && 'priority desc, '}
|
|
500
|
+
AND state < '${JOB_STATES.active}'
|
|
501
|
+
AND start_after < now()
|
|
502
|
+
ORDER BY ${priority && 'priority desc, '} created_on, id
|
|
418
503
|
LIMIT $2
|
|
419
504
|
FOR UPDATE SKIP LOCKED
|
|
420
505
|
)
|
|
421
506
|
UPDATE ${schema}.job j SET
|
|
422
|
-
state = '${
|
|
423
|
-
|
|
424
|
-
|
|
507
|
+
state = '${JOB_STATES.active}',
|
|
508
|
+
started_on = now(),
|
|
509
|
+
retry_count = CASE WHEN started_on IS NOT NULL THEN retry_count + 1 ELSE retry_count END
|
|
425
510
|
FROM next
|
|
426
511
|
WHERE name = $1 AND j.id = next.id
|
|
427
|
-
RETURNING
|
|
428
|
-
EXTRACT(epoch FROM expireIn) as expire_in_seconds
|
|
512
|
+
RETURNING j.${includeMetadata ? allJobColumns : baseJobColumns}
|
|
429
513
|
`
|
|
430
514
|
}
|
|
431
515
|
|
|
@@ -433,12 +517,12 @@ function completeJobs (schema) {
|
|
|
433
517
|
return `
|
|
434
518
|
WITH results AS (
|
|
435
519
|
UPDATE ${schema}.job
|
|
436
|
-
SET
|
|
437
|
-
state = '${
|
|
520
|
+
SET completed_on = now(),
|
|
521
|
+
state = '${JOB_STATES.completed}',
|
|
438
522
|
output = $3::jsonb
|
|
439
523
|
WHERE name = $1
|
|
440
524
|
AND id IN (SELECT UNNEST($2::uuid[]))
|
|
441
|
-
AND state = '${
|
|
525
|
+
AND state = '${JOB_STATES.active}'
|
|
442
526
|
RETURNING *
|
|
443
527
|
)
|
|
444
528
|
SELECT COUNT(*) FROM results
|
|
@@ -446,14 +530,14 @@ function completeJobs (schema) {
|
|
|
446
530
|
}
|
|
447
531
|
|
|
448
532
|
function failJobsById (schema) {
|
|
449
|
-
const where = `name = $1 AND id IN (SELECT UNNEST($2::uuid[])) AND state < '${
|
|
533
|
+
const where = `name = $1 AND id IN (SELECT UNNEST($2::uuid[])) AND state < '${JOB_STATES.completed}'`
|
|
450
534
|
const output = '$3::jsonb'
|
|
451
535
|
|
|
452
536
|
return failJobs(schema, where, output)
|
|
453
537
|
}
|
|
454
538
|
|
|
455
539
|
function failJobsByTimeout (schema) {
|
|
456
|
-
const where = `state = '${
|
|
540
|
+
const where = `state = '${JOB_STATES.active}' AND (started_on + expire_in) < now()`
|
|
457
541
|
const output = '\'{ "value": { "message": "job failed by timeout in active state" } }\'::jsonb'
|
|
458
542
|
return failJobs(schema, where, output)
|
|
459
543
|
}
|
|
@@ -463,36 +547,36 @@ function failJobs (schema, where, output) {
|
|
|
463
547
|
WITH results AS (
|
|
464
548
|
UPDATE ${schema}.job SET
|
|
465
549
|
state = CASE
|
|
466
|
-
WHEN
|
|
467
|
-
ELSE '${
|
|
550
|
+
WHEN retry_count < retry_limit THEN '${JOB_STATES.retry}'::${schema}.job_state
|
|
551
|
+
ELSE '${JOB_STATES.failed}'::${schema}.job_state
|
|
468
552
|
END,
|
|
469
|
-
|
|
470
|
-
WHEN
|
|
553
|
+
completed_on = CASE
|
|
554
|
+
WHEN retry_count < retry_limit THEN NULL
|
|
471
555
|
ELSE now()
|
|
472
556
|
END,
|
|
473
|
-
|
|
474
|
-
WHEN
|
|
475
|
-
WHEN NOT
|
|
557
|
+
start_after = CASE
|
|
558
|
+
WHEN retry_count = retry_limit THEN start_after
|
|
559
|
+
WHEN NOT retry_backoff THEN now() + retry_delay * interval '1'
|
|
476
560
|
ELSE now() + (
|
|
477
|
-
|
|
478
|
-
|
|
561
|
+
retry_delay * 2 ^ LEAST(16, retry_count + 1) / 2 +
|
|
562
|
+
retry_delay * 2 ^ LEAST(16, retry_count + 1) / 2 * random()
|
|
479
563
|
) * interval '1'
|
|
480
564
|
END,
|
|
481
565
|
output = ${output}
|
|
482
566
|
WHERE ${where}
|
|
483
567
|
RETURNING *
|
|
484
568
|
), dlq_jobs as (
|
|
485
|
-
INSERT INTO ${schema}.job (name, data, output,
|
|
569
|
+
INSERT INTO ${schema}.job (name, data, output, retry_limit, keep_until)
|
|
486
570
|
SELECT
|
|
487
|
-
|
|
571
|
+
dead_letter,
|
|
488
572
|
data,
|
|
489
573
|
output,
|
|
490
|
-
|
|
491
|
-
|
|
574
|
+
retry_limit,
|
|
575
|
+
keep_until + (keep_until - start_after)
|
|
492
576
|
FROM results
|
|
493
|
-
WHERE state = '${
|
|
494
|
-
AND
|
|
495
|
-
AND NOT name =
|
|
577
|
+
WHERE state = '${JOB_STATES.failed}'
|
|
578
|
+
AND dead_letter IS NOT NULL
|
|
579
|
+
AND NOT name = dead_letter
|
|
496
580
|
)
|
|
497
581
|
SELECT COUNT(*) FROM results
|
|
498
582
|
`
|
|
@@ -502,11 +586,11 @@ function cancelJobs (schema) {
|
|
|
502
586
|
return `
|
|
503
587
|
with results as (
|
|
504
588
|
UPDATE ${schema}.job
|
|
505
|
-
SET
|
|
506
|
-
state = '${
|
|
589
|
+
SET completed_on = now(),
|
|
590
|
+
state = '${JOB_STATES.cancelled}'
|
|
507
591
|
WHERE name = $1
|
|
508
592
|
AND id IN (SELECT UNNEST($2::uuid[]))
|
|
509
|
-
AND state < '${
|
|
593
|
+
AND state < '${JOB_STATES.completed}'
|
|
510
594
|
RETURNING 1
|
|
511
595
|
)
|
|
512
596
|
SELECT COUNT(*) from results
|
|
@@ -517,10 +601,23 @@ function resumeJobs (schema) {
|
|
|
517
601
|
return `
|
|
518
602
|
with results as (
|
|
519
603
|
UPDATE ${schema}.job
|
|
520
|
-
SET
|
|
521
|
-
state = '${
|
|
604
|
+
SET completed_on = NULL,
|
|
605
|
+
state = '${JOB_STATES.created}'
|
|
522
606
|
WHERE name = $1
|
|
523
607
|
AND id IN (SELECT UNNEST($2::uuid[]))
|
|
608
|
+
AND state = '${JOB_STATES.cancelled}'
|
|
609
|
+
RETURNING 1
|
|
610
|
+
)
|
|
611
|
+
SELECT COUNT(*) from results
|
|
612
|
+
`
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
function deleteJobs (schema) {
|
|
616
|
+
return `
|
|
617
|
+
with results as (
|
|
618
|
+
DELETE FROM ${schema}.job
|
|
619
|
+
WHERE name = $1
|
|
620
|
+
AND id IN (SELECT UNNEST($2::uuid[]))
|
|
524
621
|
RETURNING 1
|
|
525
622
|
)
|
|
526
623
|
SELECT COUNT(*) from results
|
|
@@ -534,15 +631,15 @@ function insertJob (schema) {
|
|
|
534
631
|
name,
|
|
535
632
|
data,
|
|
536
633
|
priority,
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
634
|
+
start_after,
|
|
635
|
+
singleton_key,
|
|
636
|
+
singleton_on,
|
|
637
|
+
dead_letter,
|
|
638
|
+
expire_in,
|
|
639
|
+
keep_until,
|
|
640
|
+
retry_limit,
|
|
641
|
+
retry_delay,
|
|
642
|
+
retry_backoff,
|
|
546
643
|
policy
|
|
547
644
|
)
|
|
548
645
|
SELECT
|
|
@@ -550,27 +647,27 @@ function insertJob (schema) {
|
|
|
550
647
|
j.name,
|
|
551
648
|
data,
|
|
552
649
|
priority,
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
COALESCE(
|
|
650
|
+
start_after,
|
|
651
|
+
singleton_key,
|
|
652
|
+
singleton_on,
|
|
653
|
+
COALESCE(j.dead_letter, q.dead_letter) as dead_letter,
|
|
557
654
|
CASE
|
|
558
|
-
WHEN
|
|
655
|
+
WHEN expire_in IS NOT NULL THEN CAST(expire_in as interval)
|
|
559
656
|
WHEN q.expire_seconds IS NOT NULL THEN q.expire_seconds * interval '1s'
|
|
560
|
-
WHEN
|
|
657
|
+
WHEN expire_in_default IS NOT NULL THEN CAST(expire_in_default as interval)
|
|
561
658
|
ELSE interval '15 minutes'
|
|
562
|
-
END as
|
|
659
|
+
END as expire_in,
|
|
563
660
|
CASE
|
|
564
|
-
WHEN right(
|
|
565
|
-
ELSE
|
|
566
|
-
END as
|
|
567
|
-
COALESCE(
|
|
661
|
+
WHEN right(keep_until, 1) = 'Z' THEN CAST(keep_until as timestamp with time zone)
|
|
662
|
+
ELSE start_after + CAST(COALESCE(keep_until, (q.retention_minutes * 60)::text, keep_until_default, '14 days') as interval)
|
|
663
|
+
END as keep_until,
|
|
664
|
+
COALESCE(j.retry_limit, q.retry_limit, retry_limit_default, 2) as retry_limit,
|
|
568
665
|
CASE
|
|
569
|
-
WHEN COALESCE(
|
|
570
|
-
THEN GREATEST(COALESCE(
|
|
571
|
-
ELSE COALESCE(
|
|
572
|
-
END as
|
|
573
|
-
COALESCE(
|
|
666
|
+
WHEN COALESCE(j.retry_backoff, q.retry_backoff, retry_backoff_default, false)
|
|
667
|
+
THEN GREATEST(COALESCE(j.retry_delay, q.retry_delay, retry_delay_default), 1)
|
|
668
|
+
ELSE COALESCE(j.retry_delay, q.retry_delay, retry_delay_default, 0)
|
|
669
|
+
END as retry_delay,
|
|
670
|
+
COALESCE(j.retry_backoff, q.retry_backoff, retry_backoff_default, false) as retry_backoff,
|
|
574
671
|
q.policy
|
|
575
672
|
FROM
|
|
576
673
|
( SELECT
|
|
@@ -581,24 +678,24 @@ function insertJob (schema) {
|
|
|
581
678
|
CASE
|
|
582
679
|
WHEN right($5, 1) = 'Z' THEN CAST($5 as timestamp with time zone)
|
|
583
680
|
ELSE now() + CAST(COALESCE($5,'0') as interval)
|
|
584
|
-
END as
|
|
585
|
-
$6 as
|
|
681
|
+
END as start_after,
|
|
682
|
+
$6 as singleton_key,
|
|
586
683
|
CASE
|
|
587
684
|
WHEN $7::integer IS NOT NULL THEN 'epoch'::timestamp + '1 second'::interval * ($7 * floor((date_part('epoch', now()) + $8) / $7))
|
|
588
685
|
ELSE NULL
|
|
589
|
-
END as
|
|
590
|
-
$9 as
|
|
591
|
-
$10 as
|
|
592
|
-
$11 as
|
|
593
|
-
$12 as
|
|
594
|
-
$13 as
|
|
595
|
-
$14::int as
|
|
596
|
-
$15::int as
|
|
597
|
-
$16::int as
|
|
598
|
-
$17::int as
|
|
599
|
-
$18::bool as
|
|
600
|
-
$19::bool as
|
|
601
|
-
) j
|
|
686
|
+
END as singleton_on,
|
|
687
|
+
$9 as dead_letter,
|
|
688
|
+
$10 as expire_in,
|
|
689
|
+
$11 as expire_in_default,
|
|
690
|
+
$12 as keep_until,
|
|
691
|
+
$13 as keep_until_default,
|
|
692
|
+
$14::int as retry_limit,
|
|
693
|
+
$15::int as retry_limit_default,
|
|
694
|
+
$16::int as retry_delay,
|
|
695
|
+
$17::int as retry_delay_default,
|
|
696
|
+
$18::bool as retry_backoff,
|
|
697
|
+
$19::bool as retry_backoff_default
|
|
698
|
+
) j JOIN ${schema}.queue q ON j.name = q.name
|
|
602
699
|
ON CONFLICT DO NOTHING
|
|
603
700
|
RETURNING id
|
|
604
701
|
`
|
|
@@ -608,68 +705,76 @@ function insertJobs (schema) {
|
|
|
608
705
|
return `
|
|
609
706
|
WITH defaults as (
|
|
610
707
|
SELECT
|
|
611
|
-
$2 as
|
|
612
|
-
$3 as
|
|
613
|
-
$4::int as
|
|
614
|
-
$5::int as
|
|
615
|
-
$6::bool as
|
|
708
|
+
$2 as expire_in,
|
|
709
|
+
$3 as keep_until,
|
|
710
|
+
$4::int as retry_limit,
|
|
711
|
+
$5::int as retry_delay,
|
|
712
|
+
$6::bool as retry_backoff
|
|
616
713
|
)
|
|
617
714
|
INSERT INTO ${schema}.job (
|
|
618
715
|
id,
|
|
619
716
|
name,
|
|
620
717
|
data,
|
|
621
718
|
priority,
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
719
|
+
start_after,
|
|
720
|
+
singleton_key,
|
|
721
|
+
dead_letter,
|
|
722
|
+
expire_in,
|
|
723
|
+
keep_until,
|
|
724
|
+
retry_limit,
|
|
725
|
+
retry_delay,
|
|
726
|
+
retry_backoff,
|
|
630
727
|
policy
|
|
631
728
|
)
|
|
632
729
|
SELECT
|
|
633
730
|
COALESCE(id, gen_random_uuid()) as id,
|
|
634
731
|
j.name,
|
|
635
732
|
data,
|
|
636
|
-
COALESCE(priority, 0),
|
|
637
|
-
|
|
638
|
-
"singletonKey",
|
|
639
|
-
COALESCE("deadLetter", q.dead_letter),
|
|
733
|
+
COALESCE(priority, 0) as priority,
|
|
734
|
+
j.start_after,
|
|
735
|
+
"singletonKey" as singleton_key,
|
|
736
|
+
COALESCE("deadLetter", q.dead_letter) as dead_letter,
|
|
640
737
|
CASE
|
|
641
738
|
WHEN "expireInSeconds" IS NOT NULL THEN "expireInSeconds" * interval '1s'
|
|
642
739
|
WHEN q.expire_seconds IS NOT NULL THEN q.expire_seconds * interval '1s'
|
|
643
|
-
WHEN defaults.
|
|
740
|
+
WHEN defaults.expire_in IS NOT NULL THEN CAST(defaults.expire_in as interval)
|
|
644
741
|
ELSE interval '15 minutes'
|
|
645
|
-
END as
|
|
742
|
+
END as expire_in,
|
|
646
743
|
CASE
|
|
647
744
|
WHEN "keepUntil" IS NOT NULL THEN "keepUntil"
|
|
648
|
-
ELSE COALESCE(
|
|
649
|
-
END as
|
|
650
|
-
COALESCE("retryLimit", q.retry_limit, defaults.
|
|
745
|
+
ELSE COALESCE(j.start_after, now()) + CAST(COALESCE((q.retention_minutes * 60)::text, defaults.keep_until, '14 days') as interval)
|
|
746
|
+
END as keep_until,
|
|
747
|
+
COALESCE("retryLimit", q.retry_limit, defaults.retry_limit, 2),
|
|
651
748
|
CASE
|
|
652
|
-
WHEN COALESCE("retryBackoff", q.retry_backoff, defaults.
|
|
653
|
-
THEN GREATEST(COALESCE("retryDelay", q.retry_delay, defaults.
|
|
654
|
-
ELSE COALESCE("retryDelay", q.retry_delay, defaults.
|
|
655
|
-
END as
|
|
656
|
-
COALESCE("retryBackoff", q.retry_backoff, defaults.
|
|
749
|
+
WHEN COALESCE("retryBackoff", q.retry_backoff, defaults.retry_backoff, false)
|
|
750
|
+
THEN GREATEST(COALESCE("retryDelay", q.retry_delay, defaults.retry_delay), 1)
|
|
751
|
+
ELSE COALESCE("retryDelay", q.retry_delay, defaults.retry_delay, 0)
|
|
752
|
+
END as retry_delay,
|
|
753
|
+
COALESCE("retryBackoff", q.retry_backoff, defaults.retry_backoff, false) as retry_backoff,
|
|
657
754
|
q.policy
|
|
658
|
-
FROM
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
755
|
+
FROM (
|
|
756
|
+
SELECT *,
|
|
757
|
+
CASE
|
|
758
|
+
WHEN right("startAfter", 1) = 'Z' THEN CAST("startAfter" as timestamp with time zone)
|
|
759
|
+
ELSE now() + CAST(COALESCE("startAfter",'0') as interval)
|
|
760
|
+
END as start_after
|
|
761
|
+
FROM json_to_recordset($1) as x (
|
|
762
|
+
id uuid,
|
|
763
|
+
name text,
|
|
764
|
+
priority integer,
|
|
765
|
+
data jsonb,
|
|
766
|
+
"startAfter" text,
|
|
767
|
+
"retryLimit" integer,
|
|
768
|
+
"retryDelay" integer,
|
|
769
|
+
"retryBackoff" boolean,
|
|
770
|
+
"singletonKey" text,
|
|
771
|
+
"singletonOn" text,
|
|
772
|
+
"expireInSeconds" integer,
|
|
773
|
+
"keepUntil" timestamp with time zone,
|
|
774
|
+
"deadLetter" text
|
|
775
|
+
)
|
|
776
|
+
) j
|
|
777
|
+
JOIN ${schema}.queue q ON j.name = q.name,
|
|
673
778
|
defaults
|
|
674
779
|
ON CONFLICT DO NOTHING
|
|
675
780
|
`
|
|
@@ -678,25 +783,25 @@ function insertJobs (schema) {
|
|
|
678
783
|
function drop (schema, interval) {
|
|
679
784
|
return `
|
|
680
785
|
DELETE FROM ${schema}.archive
|
|
681
|
-
WHERE
|
|
786
|
+
WHERE archived_on < (now() - interval '${interval}')
|
|
682
787
|
`
|
|
683
788
|
}
|
|
684
789
|
|
|
685
790
|
function archive (schema, completedInterval, failedInterval = completedInterval) {
|
|
791
|
+
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'
|
|
792
|
+
|
|
686
793
|
return `
|
|
687
794
|
WITH archived_rows AS (
|
|
688
795
|
DELETE FROM ${schema}.job
|
|
689
|
-
WHERE (state <> '${
|
|
690
|
-
OR (state = '${
|
|
691
|
-
OR (state < '${
|
|
796
|
+
WHERE (state <> '${JOB_STATES.failed}' AND completed_on < (now() - interval '${completedInterval}'))
|
|
797
|
+
OR (state = '${JOB_STATES.failed}' AND completed_on < (now() - interval '${failedInterval}'))
|
|
798
|
+
OR (state < '${JOB_STATES.active}' AND keep_until < now())
|
|
692
799
|
RETURNING *
|
|
693
800
|
)
|
|
694
|
-
INSERT INTO ${schema}.archive (
|
|
695
|
-
|
|
696
|
-
)
|
|
697
|
-
SELECT
|
|
698
|
-
id, name, priority, data, state, retryLimit, retryCount, retryDelay, retryBackoff, startAfter, startedOn, singletonKey, singletonOn, expireIn, createdOn, completedOn, keepUntil, deadletter, policy, output
|
|
801
|
+
INSERT INTO ${schema}.archive (${columns})
|
|
802
|
+
SELECT ${columns}
|
|
699
803
|
FROM archived_rows
|
|
804
|
+
ON CONFLICT DO NOTHING
|
|
700
805
|
`
|
|
701
806
|
}
|
|
702
807
|
|
|
@@ -716,6 +821,7 @@ function locked (schema, query) {
|
|
|
716
821
|
return `
|
|
717
822
|
BEGIN;
|
|
718
823
|
SET LOCAL lock_timeout = '30s';
|
|
824
|
+
SET LOCAL idle_in_transaction_session_timeout = '30s';
|
|
719
825
|
${advisoryLock(schema)};
|
|
720
826
|
${query};
|
|
721
827
|
COMMIT;
|
|
@@ -724,7 +830,7 @@ function locked (schema, query) {
|
|
|
724
830
|
|
|
725
831
|
function advisoryLock (schema, key) {
|
|
726
832
|
return `SELECT pg_advisory_xact_lock(
|
|
727
|
-
('x' ||
|
|
833
|
+
('x' || encode(sha224((current_database() || '.pgboss.${schema}${key || ''}')::bytea), 'hex'))::bit(64)::bigint
|
|
728
834
|
)`
|
|
729
835
|
}
|
|
730
836
|
|
|
@@ -734,13 +840,13 @@ function assertMigration (schema, version) {
|
|
|
734
840
|
}
|
|
735
841
|
|
|
736
842
|
function getJobById (schema) {
|
|
737
|
-
return
|
|
843
|
+
return getJobByTableQueueId(schema, 'job')
|
|
738
844
|
}
|
|
739
845
|
|
|
740
846
|
function getArchivedJobById (schema) {
|
|
741
|
-
return
|
|
847
|
+
return getJobByTableQueueId(schema, 'archive')
|
|
742
848
|
}
|
|
743
849
|
|
|
744
|
-
function
|
|
745
|
-
return `SELECT
|
|
850
|
+
function getJobByTableQueueId (schema, table) {
|
|
851
|
+
return `SELECT ${allJobColumns} FROM ${schema}.${table} WHERE name = $1 AND id = $2`
|
|
746
852
|
}
|