pg-boss 11.1.2 → 12.0.0-beta2
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/dist/index.cjs +2 -0
- package/dist/index.d.mts +270 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +2350 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +49 -18
- package/src/attorney.js +0 -258
- package/src/boss.js +0 -158
- package/src/contractor.js +0 -99
- package/src/db.js +0 -50
- package/src/index.js +0 -211
- package/src/manager.js +0 -697
- package/src/migrationStore.js +0 -155
- package/src/plans.js +0 -1017
- package/src/timekeeper.js +0 -203
- package/src/tools.js +0 -60
- package/src/worker.js +0 -99
- package/types.d.ts +0 -323
- package/version.json +0 -3
package/src/attorney.js
DELETED
|
@@ -1,258 +0,0 @@
|
|
|
1
|
-
const assert = require('node:assert')
|
|
2
|
-
const { DEFAULT_SCHEMA } = require('./plans')
|
|
3
|
-
|
|
4
|
-
const POLICY = {
|
|
5
|
-
MAX_EXPIRATION_HOURS: 24,
|
|
6
|
-
MIN_POLLING_INTERVAL_MS: 500,
|
|
7
|
-
MAX_RETENTION_DAYS: 365
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
module.exports = {
|
|
11
|
-
POLICY,
|
|
12
|
-
getConfig,
|
|
13
|
-
checkSendArgs,
|
|
14
|
-
validateQueueArgs,
|
|
15
|
-
checkWorkArgs,
|
|
16
|
-
checkFetchArgs,
|
|
17
|
-
assertPostgresObjectName,
|
|
18
|
-
assertQueueName,
|
|
19
|
-
assertKey
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function validateQueueArgs (config = {}) {
|
|
23
|
-
assert(!('deadLetter' in config) || config.deadLetter === null || (typeof config.deadLetter === 'string'), 'deadLetter must be a string')
|
|
24
|
-
assert(!('deadLetter' in config) || config.deadLetter === null || /[\w-]/.test(config.deadLetter), 'deadLetter can only contain alphanumeric characters, underscores, or hyphens')
|
|
25
|
-
|
|
26
|
-
validateRetryConfig(config)
|
|
27
|
-
validateExpirationConfig(config)
|
|
28
|
-
validateRetentionConfig(config)
|
|
29
|
-
validateDeletionConfig(config)
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function checkSendArgs (args) {
|
|
33
|
-
let name, data, options
|
|
34
|
-
|
|
35
|
-
if (typeof args[0] === 'string') {
|
|
36
|
-
name = args[0]
|
|
37
|
-
data = args[1]
|
|
38
|
-
|
|
39
|
-
assert(typeof data !== 'function', 'send() cannot accept a function as the payload. Did you intend to use work()?')
|
|
40
|
-
|
|
41
|
-
options = args[2]
|
|
42
|
-
} else if (typeof args[0] === 'object') {
|
|
43
|
-
assert(args.length === 1, 'send object API only accepts 1 argument')
|
|
44
|
-
|
|
45
|
-
const job = args[0]
|
|
46
|
-
|
|
47
|
-
assert(job, 'boss requires all jobs to have a name')
|
|
48
|
-
|
|
49
|
-
name = job.name
|
|
50
|
-
data = job.data
|
|
51
|
-
options = job.options
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
options = options || {}
|
|
55
|
-
|
|
56
|
-
assert(name, 'boss requires all jobs to have a queue name')
|
|
57
|
-
assert(typeof options === 'object', 'options should be an object')
|
|
58
|
-
|
|
59
|
-
options = { ...options }
|
|
60
|
-
|
|
61
|
-
assert(!('priority' in options) || (Number.isInteger(options.priority)), 'priority must be an integer')
|
|
62
|
-
options.priority = options.priority || 0
|
|
63
|
-
|
|
64
|
-
options.startAfter = (options.startAfter instanceof Date && typeof options.startAfter.toISOString === 'function')
|
|
65
|
-
? options.startAfter.toISOString()
|
|
66
|
-
: (options.startAfter > 0)
|
|
67
|
-
? '' + options.startAfter
|
|
68
|
-
: (typeof options.startAfter === 'string')
|
|
69
|
-
? options.startAfter
|
|
70
|
-
: null
|
|
71
|
-
|
|
72
|
-
validateRetryConfig(options)
|
|
73
|
-
validateExpirationConfig(options)
|
|
74
|
-
validateRetentionConfig(options)
|
|
75
|
-
validateDeletionConfig(options)
|
|
76
|
-
|
|
77
|
-
return { name, data, options }
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function checkWorkArgs (name, args) {
|
|
81
|
-
let options, callback
|
|
82
|
-
|
|
83
|
-
assert(name, 'missing job name')
|
|
84
|
-
|
|
85
|
-
if (args.length === 1) {
|
|
86
|
-
callback = args[0]
|
|
87
|
-
options = {}
|
|
88
|
-
} else if (args.length > 1) {
|
|
89
|
-
options = args[0] || {}
|
|
90
|
-
callback = args[1]
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
assert(typeof callback === 'function', 'expected callback to be a function')
|
|
94
|
-
assert(typeof options === 'object', 'expected config to be an object')
|
|
95
|
-
|
|
96
|
-
options = { ...options }
|
|
97
|
-
|
|
98
|
-
applyPollingInterval(options)
|
|
99
|
-
|
|
100
|
-
assert(!('batchSize' in options) || (Number.isInteger(options.batchSize) && options.batchSize >= 1), 'batchSize must be an integer > 0')
|
|
101
|
-
assert(!('includeMetadata' in options) || typeof options.includeMetadata === 'boolean', 'includeMetadata must be a boolean')
|
|
102
|
-
assert(!('priority' in options) || typeof options.priority === 'boolean', 'priority must be a boolean')
|
|
103
|
-
|
|
104
|
-
options.batchSize = options.batchSize || 1
|
|
105
|
-
|
|
106
|
-
return { options, callback }
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function checkFetchArgs (name, options) {
|
|
110
|
-
assert(name, 'missing queue name')
|
|
111
|
-
|
|
112
|
-
assert(!('batchSize' in options) || (Number.isInteger(options.batchSize) && options.batchSize >= 1), 'batchSize must be an integer > 0')
|
|
113
|
-
assert(!('includeMetadata' in options) || typeof options.includeMetadata === 'boolean', 'includeMetadata must be a boolean')
|
|
114
|
-
assert(!('priority' in options) || typeof options.priority === 'boolean', 'priority must be a boolean')
|
|
115
|
-
assert(!('ignoreStartAfter' in options) || typeof options.ignoreStartAfter === 'boolean', 'ignoreStartAfter must be a boolean')
|
|
116
|
-
|
|
117
|
-
options.batchSize = options.batchSize || 1
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
function getConfig (value) {
|
|
121
|
-
assert(value && (typeof value === 'object' || typeof value === 'string'),
|
|
122
|
-
'configuration assert: string or config object is required to connect to postgres')
|
|
123
|
-
|
|
124
|
-
const config = (typeof value === 'string')
|
|
125
|
-
? { connectionString: value }
|
|
126
|
-
: { ...value }
|
|
127
|
-
|
|
128
|
-
config.schedule = ('schedule' in config) ? config.schedule : true
|
|
129
|
-
config.supervise = ('supervise' in config) ? config.supervise : true
|
|
130
|
-
config.migrate = ('migrate' in config) ? config.migrate : true
|
|
131
|
-
|
|
132
|
-
applySchemaConfig(config)
|
|
133
|
-
applyOpsConfig(config)
|
|
134
|
-
applyScheduleConfig(config)
|
|
135
|
-
validateWarningConfig(config)
|
|
136
|
-
|
|
137
|
-
return config
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
function applySchemaConfig (config) {
|
|
141
|
-
if (config.schema) {
|
|
142
|
-
assertPostgresObjectName(config.schema)
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
config.schema = config.schema || DEFAULT_SCHEMA
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
function validateWarningConfig (config) {
|
|
149
|
-
assert(!('warningQueueSize' in config) || config.warningQueueSize >= 1,
|
|
150
|
-
'configuration assert: warningQueueSize must be at least 1')
|
|
151
|
-
|
|
152
|
-
assert(!('warningSlowQuerySeconds' in config) || config.warningSlowQuerySeconds >= 1,
|
|
153
|
-
'configuration assert: warningSlowQuerySeconds must be at least 1')
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
function assertPostgresObjectName (name) {
|
|
157
|
-
assert(typeof name === 'string', 'Name must be a string')
|
|
158
|
-
assert(name.length <= 50, 'Name cannot exceed 50 characters')
|
|
159
|
-
assert(!/\W/.test(name), 'Name can only contain alphanumeric characters or underscores')
|
|
160
|
-
assert(!/^\d/.test(name), 'Name cannot start with a number')
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
function assertQueueName (name) {
|
|
164
|
-
assert(name, 'Name is required')
|
|
165
|
-
assert(typeof name === 'string', 'Name must be a string')
|
|
166
|
-
assert(/[\w-]/.test(name), 'Name can only contain alphanumeric characters, underscores, or hyphens')
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
function assertKey (key) {
|
|
170
|
-
if (!key) return
|
|
171
|
-
assert(typeof key === 'string', 'Key must be a string')
|
|
172
|
-
assert(/[\w-]/.test(key), 'Key can only contain alphanumeric characters, underscores, or hyphens')
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
function validateRetentionConfig (config) {
|
|
176
|
-
assert(!('retentionSeconds' in config) || config.retentionSeconds >= 1,
|
|
177
|
-
'configuration assert: retentionSeconds must be at least every second')
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
function validateExpirationConfig (config) {
|
|
181
|
-
assert(!('expireInSeconds' in config) || config.expireInSeconds >= 1,
|
|
182
|
-
'configuration assert: expireInSeconds must be at least every second')
|
|
183
|
-
|
|
184
|
-
assert(!config.expireInSeconds || config.expireInSeconds / 60 / 60 < POLICY.MAX_EXPIRATION_HOURS, `configuration assert: expiration cannot exceed ${POLICY.MAX_EXPIRATION_HOURS} hours`)
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
function validateRetryConfig (config) {
|
|
188
|
-
assert(!('retryDelay' in config) || (Number.isInteger(config.retryDelay) && config.retryDelay >= 0), 'retryDelay must be an integer >= 0')
|
|
189
|
-
assert(!('retryLimit' in config) || (Number.isInteger(config.retryLimit) && config.retryLimit >= 0), 'retryLimit must be an integer >= 0')
|
|
190
|
-
assert(!('retryBackoff' in config) || (config.retryBackoff === true || config.retryBackoff === false), 'retryBackoff must be either true or false')
|
|
191
|
-
assert(!('retryDelayMax' in config) || config.retryDelayMax === null || config.retryBackoff === true, 'retryDelayMax can only be set if retryBackoff is true')
|
|
192
|
-
assert(!('retryDelayMax' in config) || config.retryDelayMax === null || (Number.isInteger(config.retryDelayMax) && config.retryDelayMax >= 0), 'retryDelayMax must be an integer >= 0')
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
function applyPollingInterval (config) {
|
|
196
|
-
assert(!('pollingIntervalSeconds' in config) || config.pollingIntervalSeconds >= POLICY.MIN_POLLING_INTERVAL_MS / 1000,
|
|
197
|
-
`configuration assert: pollingIntervalSeconds must be at least every ${POLICY.MIN_POLLING_INTERVAL_MS}ms`)
|
|
198
|
-
|
|
199
|
-
config.pollingInterval = ('pollingIntervalSeconds' in config)
|
|
200
|
-
? config.pollingIntervalSeconds * 1000
|
|
201
|
-
: 2000
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
function applyOpsConfig (config) {
|
|
205
|
-
assert(!('superviseIntervalSeconds' in config) || config.superviseIntervalSeconds >= 1,
|
|
206
|
-
'configuration assert: superviseIntervalSeconds must be at least every second')
|
|
207
|
-
|
|
208
|
-
config.superviseIntervalSeconds = config.superviseIntervalSeconds || 60
|
|
209
|
-
|
|
210
|
-
assert(config.superviseIntervalSeconds / 60 / 60 <= POLICY.MAX_EXPIRATION_HOURS,
|
|
211
|
-
`configuration assert: superviseIntervalSeconds cannot exceed ${POLICY.MAX_EXPIRATION_HOURS} hours`)
|
|
212
|
-
|
|
213
|
-
assert(!('maintenanceIntervalSeconds' in config) || config.maintenanceIntervalSeconds >= 1,
|
|
214
|
-
'configuration assert: maintenanceIntervalSeconds must be at least every second')
|
|
215
|
-
|
|
216
|
-
config.maintenanceIntervalSeconds = config.maintenanceIntervalSeconds || POLICY.MAX_EXPIRATION_HOURS * 60 * 60
|
|
217
|
-
|
|
218
|
-
assert(config.maintenanceIntervalSeconds / 60 / 60 <= POLICY.MAX_EXPIRATION_HOURS,
|
|
219
|
-
`configuration assert: maintenanceIntervalSeconds cannot exceed ${POLICY.MAX_EXPIRATION_HOURS} hours`)
|
|
220
|
-
|
|
221
|
-
assert(!('monitorIntervalSeconds' in config) || config.monitorIntervalSeconds >= 1,
|
|
222
|
-
'configuration assert: monitorIntervalSeconds must be at least every second')
|
|
223
|
-
|
|
224
|
-
config.monitorIntervalSeconds = config.monitorIntervalSeconds || 60
|
|
225
|
-
|
|
226
|
-
assert(config.monitorIntervalSeconds / 60 / 60 <= POLICY.MAX_EXPIRATION_HOURS,
|
|
227
|
-
`configuration assert: monitorIntervalSeconds cannot exceed ${POLICY.MAX_EXPIRATION_HOURS} hours`)
|
|
228
|
-
|
|
229
|
-
assert(!('queueCacheIntervalSeconds' in config) || config.queueCacheIntervalSeconds >= 1,
|
|
230
|
-
'configuration assert: queueCacheIntervalSeconds must be at least every second')
|
|
231
|
-
|
|
232
|
-
config.queueCacheIntervalSeconds = config.queueCacheIntervalSeconds || 60
|
|
233
|
-
|
|
234
|
-
assert(config.queueCacheIntervalSeconds / 60 / 60 <= POLICY.MAX_EXPIRATION_HOURS,
|
|
235
|
-
`configuration assert: queueCacheIntervalSeconds cannot exceed ${POLICY.MAX_EXPIRATION_HOURS} hours`)
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
function validateDeletionConfig (config) {
|
|
239
|
-
assert(!('deleteAfterSeconds' in config) || config.deleteAfterSeconds >= 1,
|
|
240
|
-
'configuration assert: deleteAfterSeconds must be at least every second')
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
function applyScheduleConfig (config) {
|
|
244
|
-
assert(!('clockMonitorIntervalSeconds' in config) || (config.clockMonitorIntervalSeconds >= 1 && config.clockMonitorIntervalSeconds <= 600),
|
|
245
|
-
'configuration assert: clockMonitorIntervalSeconds must be between 1 second and 10 minutes')
|
|
246
|
-
|
|
247
|
-
config.clockMonitorIntervalSeconds = config.clockMonitorIntervalSeconds || 600
|
|
248
|
-
|
|
249
|
-
assert(!('cronMonitorIntervalSeconds' in config) || (config.cronMonitorIntervalSeconds >= 1 && config.cronMonitorIntervalSeconds <= 45),
|
|
250
|
-
'configuration assert: cronMonitorIntervalSeconds must be between 1 and 45 seconds')
|
|
251
|
-
|
|
252
|
-
config.cronMonitorIntervalSeconds = config.cronMonitorIntervalSeconds || 30
|
|
253
|
-
|
|
254
|
-
assert(!('cronWorkerIntervalSeconds' in config) || (config.cronWorkerIntervalSeconds >= 1 && config.cronWorkerIntervalSeconds <= 45),
|
|
255
|
-
'configuration assert: cronWorkerIntervalSeconds must be between 1 and 45 seconds')
|
|
256
|
-
|
|
257
|
-
config.cronWorkerIntervalSeconds = config.cronWorkerIntervalSeconds || 5
|
|
258
|
-
}
|
package/src/boss.js
DELETED
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
const EventEmitter = require('node:events')
|
|
2
|
-
const plans = require('./plans')
|
|
3
|
-
const { unwrapSQLResult } = require('./tools')
|
|
4
|
-
|
|
5
|
-
const events = {
|
|
6
|
-
error: 'error',
|
|
7
|
-
warning: 'warning'
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
const WARNINGS = {
|
|
11
|
-
SLOW_QUERY: { seconds: 30, message: 'Warning: slow query. Your queues and/or database server should be reviewed' },
|
|
12
|
-
LARGE_QUEUE: { size: 10_000, mesasge: 'Warning: large queue backlog. Your queue should be reviewed' }
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
class Boss extends EventEmitter {
|
|
16
|
-
#stopped
|
|
17
|
-
#maintaining
|
|
18
|
-
#superviseInterval
|
|
19
|
-
#db
|
|
20
|
-
#config
|
|
21
|
-
#manager
|
|
22
|
-
|
|
23
|
-
constructor (db, config) {
|
|
24
|
-
super()
|
|
25
|
-
|
|
26
|
-
this.#db = db
|
|
27
|
-
this.#config = config
|
|
28
|
-
this.#manager = config.manager
|
|
29
|
-
this.#stopped = true
|
|
30
|
-
|
|
31
|
-
this.events = events
|
|
32
|
-
this.functions = [
|
|
33
|
-
this.supervise
|
|
34
|
-
]
|
|
35
|
-
|
|
36
|
-
if (config.warningSlowQuerySeconds) {
|
|
37
|
-
WARNINGS.SLOW_QUERY.seconds = config.warningSlowQuerySeconds
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
if (config.warningQueueSize) {
|
|
41
|
-
WARNINGS.LARGE_QUEUE.size = config.warningQueueSize
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
async start () {
|
|
46
|
-
if (this.#stopped) {
|
|
47
|
-
this.#superviseInterval = setInterval(() => this.#onSupervise(), this.#config.superviseIntervalSeconds * 1000)
|
|
48
|
-
this.#stopped = false
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
async stop () {
|
|
53
|
-
if (!this.#stopped) {
|
|
54
|
-
if (this.#superviseInterval) clearInterval(this.#superviseInterval)
|
|
55
|
-
this.#stopped = true
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
async #executeSql (sql, values) {
|
|
60
|
-
const started = Date.now()
|
|
61
|
-
|
|
62
|
-
const result = unwrapSQLResult(await this.#db.executeSql(sql, values))
|
|
63
|
-
|
|
64
|
-
const ended = Date.now()
|
|
65
|
-
|
|
66
|
-
const elapsed = (ended - started) / 1000
|
|
67
|
-
|
|
68
|
-
if (elapsed > WARNINGS.SLOW_QUERY.seconds || this.#config.__test__warn_slow_query) {
|
|
69
|
-
this.emit(events.warning, { message: WARNINGS.SLOW_QUERY.message, data: { elapsed, sql, values } })
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
return result
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
async #onSupervise () {
|
|
76
|
-
try {
|
|
77
|
-
if (this.#stopped) return
|
|
78
|
-
if (this.#maintaining) return
|
|
79
|
-
if (this.#config.__test__throw_maint) throw new Error(this.#config.__test__throw_maint)
|
|
80
|
-
|
|
81
|
-
this.#maintaining = true
|
|
82
|
-
|
|
83
|
-
const queues = await this.#manager.getQueues()
|
|
84
|
-
|
|
85
|
-
for (const queue of queues) {
|
|
86
|
-
!this.#stopped && await this.supervise(queue)
|
|
87
|
-
}
|
|
88
|
-
} catch (err) {
|
|
89
|
-
this.emit(events.error, err)
|
|
90
|
-
} finally {
|
|
91
|
-
this.#maintaining = false
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
async supervise (value) {
|
|
96
|
-
let queues
|
|
97
|
-
|
|
98
|
-
if (!value) {
|
|
99
|
-
queues = await this.#manager.getQueues()
|
|
100
|
-
} if (typeof value === 'string') {
|
|
101
|
-
queues = await this.#manager.getQueues(value)
|
|
102
|
-
} else if (typeof value === 'object') {
|
|
103
|
-
queues = [value]
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
const queueGroups = queues.reduce((acc, q) => {
|
|
107
|
-
const { table } = q
|
|
108
|
-
acc[table] = acc[table] || { table, queues: [] }
|
|
109
|
-
acc[table].queues.push(q)
|
|
110
|
-
return acc
|
|
111
|
-
}, {})
|
|
112
|
-
|
|
113
|
-
for (const queueGroup of Object.values(queueGroups)) {
|
|
114
|
-
const { table, queues } = queueGroup
|
|
115
|
-
const names = queues.map(i => i.name)
|
|
116
|
-
|
|
117
|
-
while (names.length) {
|
|
118
|
-
const chunk = names.splice(0, 100)
|
|
119
|
-
|
|
120
|
-
await this.#monitor(table, chunk)
|
|
121
|
-
await this.#maintain(table, chunk)
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
async #monitor (table, names) {
|
|
127
|
-
const command = plans.trySetQueueMonitorTime(this.#config.schema, names, this.#config.monitorIntervalSeconds)
|
|
128
|
-
const { rows } = await this.#executeSql(command)
|
|
129
|
-
|
|
130
|
-
if (rows.length) {
|
|
131
|
-
const queues = rows.map(q => q.name)
|
|
132
|
-
|
|
133
|
-
const cacheStatsSql = plans.cacheQueueStats(this.#config.schema, table, queues)
|
|
134
|
-
const { rows: rowsCacheStats } = await this.#executeSql(cacheStatsSql)
|
|
135
|
-
const warnings = rowsCacheStats.filter(i => i.queuedCount > (i.warningQueueSize || WARNINGS.LARGE_QUEUE.size))
|
|
136
|
-
|
|
137
|
-
for (const warning of warnings) {
|
|
138
|
-
this.emit(events.warning, { message: WARNINGS.LARGE_QUEUE.mesasge, data: warning })
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
const sql = plans.failJobsByTimeout(this.#config.schema, table, queues)
|
|
142
|
-
await this.#executeSql(sql)
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
async #maintain (table, names) {
|
|
147
|
-
const command = plans.trySetQueueDeletionTime(this.#config.schema, names, this.#config.maintenanceIntervalSeconds)
|
|
148
|
-
const { rows } = await this.#executeSql(command)
|
|
149
|
-
|
|
150
|
-
if (rows.length) {
|
|
151
|
-
const queues = rows.map(q => q.name)
|
|
152
|
-
const sql = plans.deletion(this.#config.schema, table, queues)
|
|
153
|
-
await this.#executeSql(sql)
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
module.exports = Boss
|
package/src/contractor.js
DELETED
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
const assert = require('node:assert')
|
|
2
|
-
const plans = require('./plans')
|
|
3
|
-
const { DEFAULT_SCHEMA } = plans
|
|
4
|
-
const migrationStore = require('./migrationStore')
|
|
5
|
-
const schemaVersion = require('../version.json').schema
|
|
6
|
-
|
|
7
|
-
class Contractor {
|
|
8
|
-
static constructionPlans (schema = DEFAULT_SCHEMA) {
|
|
9
|
-
return plans.create(schema, schemaVersion)
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
static migrationPlans (schema = DEFAULT_SCHEMA, version = schemaVersion - 1) {
|
|
13
|
-
return migrationStore.migrate(schema, version)
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
static rollbackPlans (schema = DEFAULT_SCHEMA, version = schemaVersion) {
|
|
17
|
-
return migrationStore.rollback(schema, version)
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
constructor (db, config) {
|
|
21
|
-
this.config = config
|
|
22
|
-
this.db = db
|
|
23
|
-
this.migrations = this.config.migrations || migrationStore.getAll(this.config.schema)
|
|
24
|
-
|
|
25
|
-
// exported api to index
|
|
26
|
-
this.functions = [
|
|
27
|
-
this.schemaVersion,
|
|
28
|
-
this.isInstalled
|
|
29
|
-
]
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
async schemaVersion () {
|
|
33
|
-
const result = await this.db.executeSql(plans.getVersion(this.config.schema))
|
|
34
|
-
return result.rows.length ? parseInt(result.rows[0].version) : null
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
async isInstalled () {
|
|
38
|
-
const result = await this.db.executeSql(plans.versionTableExists(this.config.schema))
|
|
39
|
-
return !!result.rows[0].name
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
async start () {
|
|
43
|
-
const installed = await this.isInstalled()
|
|
44
|
-
|
|
45
|
-
if (installed) {
|
|
46
|
-
const version = await this.schemaVersion()
|
|
47
|
-
|
|
48
|
-
if (schemaVersion > version) {
|
|
49
|
-
await this.migrate(version)
|
|
50
|
-
}
|
|
51
|
-
} else {
|
|
52
|
-
await this.create()
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
async check () {
|
|
57
|
-
const installed = await this.isInstalled()
|
|
58
|
-
|
|
59
|
-
if (!installed) {
|
|
60
|
-
throw new Error('pg-boss is not installed')
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const version = await this.schemaVersion()
|
|
64
|
-
|
|
65
|
-
if (schemaVersion !== version) {
|
|
66
|
-
throw new Error('pg-boss database requires migrations')
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
async create () {
|
|
71
|
-
try {
|
|
72
|
-
const commands = plans.create(this.config.schema, schemaVersion)
|
|
73
|
-
await this.db.executeSql(commands)
|
|
74
|
-
} catch (err) {
|
|
75
|
-
assert(err.message.includes(plans.CREATE_RACE_MESSAGE), err)
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
async migrate (version) {
|
|
80
|
-
try {
|
|
81
|
-
const commands = migrationStore.migrate(this.config, version, this.migrations)
|
|
82
|
-
await this.db.executeSql(commands)
|
|
83
|
-
} catch (err) {
|
|
84
|
-
assert(err.message.includes(plans.MIGRATE_RACE_MESSAGE), err)
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
async next (version) {
|
|
89
|
-
const commands = migrationStore.next(this.config.schema, version, this.migrations)
|
|
90
|
-
await this.db.executeSql(commands)
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
async rollback (version) {
|
|
94
|
-
const commands = migrationStore.rollback(this.config.schema, version, this.migrations)
|
|
95
|
-
await this.db.executeSql(commands)
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
module.exports = Contractor
|
package/src/db.js
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
const EventEmitter = require('node:events')
|
|
2
|
-
const pg = require('pg')
|
|
3
|
-
|
|
4
|
-
class Db extends EventEmitter {
|
|
5
|
-
constructor (config) {
|
|
6
|
-
super()
|
|
7
|
-
|
|
8
|
-
config.application_name = config.application_name || 'pgboss'
|
|
9
|
-
// config.maxUses = config.maxUses || 1000
|
|
10
|
-
|
|
11
|
-
this.config = config
|
|
12
|
-
this._pgbdb = true
|
|
13
|
-
this.opened = false
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
events = {
|
|
17
|
-
error: 'error'
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
async open () {
|
|
21
|
-
this.pool = new pg.Pool(this.config)
|
|
22
|
-
this.pool.on('error', error => this.emit('error', error))
|
|
23
|
-
this.opened = true
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
async close () {
|
|
27
|
-
if (!this.pool.ending) {
|
|
28
|
-
this.opened = false
|
|
29
|
-
await this.pool.end()
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
async executeSql (text, values) {
|
|
34
|
-
if (this.opened) {
|
|
35
|
-
// if (this.config.debug === true) {
|
|
36
|
-
// console.log(`${new Date().toISOString()}: DEBUG SQL`)
|
|
37
|
-
// console.log(text)
|
|
38
|
-
|
|
39
|
-
// if (values) {
|
|
40
|
-
// console.log(`${new Date().toISOString()}: DEBUG VALUES`)
|
|
41
|
-
// console.log(values)
|
|
42
|
-
// }
|
|
43
|
-
// }
|
|
44
|
-
|
|
45
|
-
return await this.pool.query(text, values)
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
module.exports = Db
|