pg-boss 9.0.3 → 10.0.0-beta10

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/src/index.js CHANGED
@@ -6,13 +6,24 @@ const Manager = require('./manager')
6
6
  const Timekeeper = require('./timekeeper')
7
7
  const Boss = require('./boss')
8
8
  const Db = require('./db')
9
- const delay = require('delay')
9
+ const { delay } = require('./tools')
10
10
 
11
11
  const events = {
12
12
  error: 'error',
13
13
  stopped: 'stopped'
14
14
  }
15
15
  class PgBoss extends EventEmitter {
16
+ #stoppingOn
17
+ #stopped
18
+ #starting
19
+ #started
20
+ #config
21
+ #db
22
+ #boss
23
+ #contractor
24
+ #manager
25
+ #timekeeper
26
+
16
27
  static getConstructionPlans (schema) {
17
28
  return Contractor.constructionPlans(schema)
18
29
  }
@@ -25,158 +36,182 @@ class PgBoss extends EventEmitter {
25
36
  return Contractor.rollbackPlans(schema, version)
26
37
  }
27
38
 
28
- constructor (value) {
29
- const config = Attorney.getConfig(value)
39
+ static states = plans.JOB_STATES
40
+ static policies = plans.QUEUE_POLICIES
30
41
 
42
+ constructor (value) {
31
43
  super()
32
44
 
33
- const db = getDb(config)
45
+ this.#stoppingOn = null
46
+ this.#stopped = true
47
+
48
+ const config = Attorney.getConfig(value)
49
+ this.#config = config
50
+
51
+ const db = this.getDb()
52
+ this.#db = db
34
53
 
35
54
  if (db.isOurs) {
36
- promoteEvent.call(this, db, 'error')
55
+ this.#promoteEvents(db)
37
56
  }
38
57
 
39
- const manager = new Manager(db, config)
40
- Object.keys(manager.events).forEach(event => promoteEvent.call(this, manager, manager.events[event]))
41
- manager.functions.forEach(func => promoteFunction.call(this, manager, func))
58
+ const contractor = new Contractor(db, config)
42
59
 
60
+ const manager = new Manager(db, config)
43
61
  const bossConfig = { ...config, manager }
44
62
 
45
63
  const boss = new Boss(db, bossConfig)
46
- Object.keys(boss.events).forEach(event => promoteEvent.call(this, boss, boss.events[event]))
47
- boss.functions.forEach(func => promoteFunction.call(this, boss, func))
48
64
 
49
65
  const timekeeper = new Timekeeper(db, bossConfig)
50
- Object.keys(timekeeper.events).forEach(event => promoteEvent.call(this, timekeeper, timekeeper.events[event]))
51
- timekeeper.functions.forEach(func => promoteFunction.call(this, timekeeper, func))
52
-
53
66
  manager.timekeeper = timekeeper
54
67
 
55
- this.stoppingOn = null
56
- this.stopped = true
57
- this.config = config
58
- this.db = db
59
- this.boss = boss
60
- this.contractor = new Contractor(db, config)
61
- this.manager = manager
62
- this.timekeeper = timekeeper
63
-
64
- function getDb (config) {
65
- if (config.db) {
66
- return config.db
67
- }
68
+ this.#promoteEvents(manager)
69
+ this.#promoteEvents(boss)
70
+ this.#promoteEvents(timekeeper)
68
71
 
69
- const db = new Db(config)
70
- db.isOurs = true
71
- return db
72
- }
72
+ this.#promoteFunctions(boss)
73
+ this.#promoteFunctions(contractor)
74
+ this.#promoteFunctions(manager)
75
+ this.#promoteFunctions(timekeeper)
73
76
 
74
- function promoteFunction (obj, func) {
75
- this[func.name] = (...args) => {
76
- const shouldRun = !this.started || !((func.name === 'work' || func.name === 'onComplete') && (this.stopped || this.stoppingOn))
77
+ this.#boss = boss
78
+ this.#contractor = contractor
79
+ this.#manager = manager
80
+ this.#timekeeper = timekeeper
81
+ }
77
82
 
78
- if (shouldRun) {
79
- return func.apply(obj, args)
80
- } else {
81
- const state = this.stoppingOn ? 'stopping' : this.stopped ? 'stopped' : !this.started ? 'not started' : 'started'
82
- return Promise.reject(new Error(`pg-boss is ${state}.`))
83
- }
84
- }
83
+ getDb () {
84
+ if (this.#db) {
85
+ return this.#db
86
+ }
87
+
88
+ if (this.#config.db) {
89
+ return this.#config.db
85
90
  }
86
91
 
87
- function promoteEvent (emitter, event) {
92
+ const db = new Db(this.#config)
93
+ db.isOurs = true
94
+ return db
95
+ }
96
+
97
+ #promoteEvents (emitter) {
98
+ for (const event of Object.values(emitter?.events)) {
88
99
  emitter.on(event, arg => this.emit(event, arg))
89
100
  }
90
101
  }
91
102
 
103
+ #promoteFunctions (obj) {
104
+ for (const func of obj?.functions) {
105
+ this[func.name] = (...args) => func.apply(obj, args)
106
+ }
107
+ }
108
+
92
109
  async start () {
93
- if (!this.stopped) {
94
- return this
110
+ if (this.#starting || this.#started) {
111
+ return
95
112
  }
96
113
 
97
- if (this.db.isOurs && !this.db.opened) {
98
- await this.db.open()
114
+ this.#starting = true
115
+
116
+ if (this.#db.isOurs && !this.#db.opened) {
117
+ await this.#db.open()
99
118
  }
100
119
 
101
- await this.contractor.start()
120
+ if (this.#config.migrate) {
121
+ await this.#contractor.start()
122
+ } else {
123
+ await this.#contractor.check()
124
+ }
102
125
 
103
- this.stopped = false
104
- this.started = true
126
+ this.#manager.start()
105
127
 
106
- this.manager.start()
128
+ if (this.#config.supervise) {
129
+ await this.#boss.supervise()
130
+ }
107
131
 
108
- if (!this.config.noSupervisor) {
109
- await this.boss.supervise()
132
+ if (this.#config.monitorStateIntervalSeconds) {
133
+ await this.#boss.monitor()
110
134
  }
111
135
 
112
- if (!this.config.noScheduling) {
113
- await this.timekeeper.start()
136
+ if (this.#config.schedule) {
137
+ await this.#timekeeper.start()
114
138
  }
115
139
 
140
+ this.#starting = false
141
+ this.#started = true
142
+ this.#stopped = false
143
+
116
144
  return this
117
145
  }
118
146
 
119
147
  async stop (options = {}) {
120
- if (this.stoppingOn) {
148
+ if (this.#stoppingOn || this.#stopped) {
121
149
  return
122
150
  }
123
151
 
124
- if (this.stopped) {
125
- this.emit(events.stopped)
126
- }
127
-
128
- let { destroy = false, graceful = true, timeout = 30000 } = options
152
+ let { destroy = false, graceful = true, timeout = 30000, wait = true } = options
129
153
 
130
154
  timeout = Math.max(timeout, 1000)
131
155
 
132
- this.stoppingOn = Date.now()
156
+ this.#stoppingOn = Date.now()
133
157
 
134
- await this.manager.stop()
135
- await this.timekeeper.stop()
158
+ await this.#manager.stop()
159
+ await this.#timekeeper.stop()
160
+ await this.#boss.stop()
136
161
 
137
- const shutdown = async () => {
138
- this.stopped = true
139
- this.stoppingOn = null
162
+ await new Promise((resolve, reject) => {
163
+ const shutdown = async () => {
164
+ try {
165
+ if (this.#config.__test__throw_shutdown) {
166
+ throw new Error(this.#config.__test__throw_shutdown)
167
+ }
140
168
 
141
- if (this.db.isOurs && this.db.opened && destroy) {
142
- await this.db.close()
143
- }
169
+ await this.#manager.failWip()
144
170
 
145
- this.emit(events.stopped)
146
- }
171
+ if (this.#db.isOurs && this.#db.opened && destroy) {
172
+ await this.#db.close()
173
+ }
147
174
 
148
- if (!graceful) {
149
- await this.boss.stop()
150
- await shutdown()
151
- return
152
- }
175
+ this.#stopped = true
176
+ this.#stoppingOn = null
177
+ this.#started = false
153
178
 
154
- setImmediate(async () => {
155
- let closing = false
179
+ this.emit(events.stopped)
180
+ resolve()
181
+ } catch (err) {
182
+ this.emit(events.error, err)
183
+ reject(err)
184
+ }
185
+ }
156
186
 
157
- try {
158
- while (Date.now() - this.stoppingOn < timeout) {
159
- if (this.manager.getWipData({ includeInternal: closing }).length === 0) {
160
- if (closing) {
161
- break
162
- }
187
+ if (!graceful) {
188
+ return shutdown()
189
+ }
163
190
 
164
- closing = true
191
+ if (!wait) {
192
+ resolve()
193
+ }
165
194
 
166
- await this.boss.stop()
195
+ setImmediate(async () => {
196
+ try {
197
+ if (this.#config.__test__throw_stop_monitor) {
198
+ throw new Error(this.#config.__test__throw_stop_monitor)
167
199
  }
168
200
 
169
- await delay(1000)
170
- }
201
+ const isWip = () => this.#manager.getWipData({ includeInternal: false }).length > 0
171
202
 
172
- await this.boss.stop()
173
- await shutdown()
174
- } catch (err) {
175
- this.emit(events.error, err)
176
- }
203
+ while ((Date.now() - this.#stoppingOn) < timeout && isWip()) {
204
+ await delay(500)
205
+ }
206
+
207
+ await shutdown()
208
+ } catch (err) {
209
+ reject(err)
210
+ this.emit(events.error, err)
211
+ }
212
+ })
177
213
  })
178
214
  }
179
215
  }
180
216
 
181
217
  module.exports = PgBoss
182
- module.exports.states = plans.states