feat(mixins/Hooks): start* listeners can return teardown functions

This commit is contained in:
Julien Fontanet
2023-04-12 15:57:59 +02:00
parent 68b2c287eb
commit 86aaa50946
3 changed files with 29 additions and 11 deletions

View File

@@ -1,18 +1,22 @@
import assert from 'assert' import assert from 'assert'
import emitAsync from '@xen-orchestra/emit-async'
import EventEmitter from 'events' import EventEmitter from 'events'
import { createLogger } from '@xen-orchestra/log' import { createLogger } from '@xen-orchestra/log'
const { debug, warn } = createLogger('xo:mixins:hooks') const { debug, warn } = createLogger('xo:mixins:hooks')
const runHook = async (emitter, hook) => { const noop = Function.prototype
const runHook = async (emitter, hook, onResult = noop) => {
debug(`${hook} start…`) debug(`${hook} start…`)
await emitAsync.call( const listeners = emitter.listeners(hook)
emitter, await Promise.all(
{ listeners.map(async listener => {
onError: error => warn(`${hook} failure`, { error }), try {
}, onResult(await listener.call(emitter))
hook } catch (error) {
warn(`${hook} failure`, { error })
}
})
) )
debug(`${hook} finished`) debug(`${hook} finished`)
} }
@@ -31,6 +35,9 @@ export default class Hooks extends EventEmitter {
// //
// They initialize the application. // They initialize the application.
// //
// A *start* listener can return a teardown function which will be added as a
// one-time listener for the *stop* event.
//
// *startCore* is automatically called if necessary. // *startCore* is automatically called if necessary.
async start() { async start() {
if (this._status === 'stopped') { if (this._status === 'stopped') {
@@ -39,7 +46,11 @@ export default class Hooks extends EventEmitter {
assert.strictEqual(this._status, 'core started') assert.strictEqual(this._status, 'core started')
} }
this._status = 'starting' this._status = 'starting'
await runHook(this, 'start') await runHook(this, 'start', result => {
if (typeof result === 'function') {
this.once('stop', result)
}
})
this.emit((this._status = 'started')) this.emit((this._status = 'started'))
} }
@@ -47,10 +58,17 @@ export default class Hooks extends EventEmitter {
// //
// They initialize core features of the application (connect to databases, // They initialize core features of the application (connect to databases,
// etc.) and should be fast and side-effects free. // etc.) and should be fast and side-effects free.
//
// A *start core* listener can return a teardown function which will be added
// as a one-time listener for the *stop core* event.
async startCore() { async startCore() {
assert.strictEqual(this._status, 'stopped') assert.strictEqual(this._status, 'stopped')
this._status = 'starting core' this._status = 'starting core'
await runHook(this, 'start core') await runHook(this, 'start core', result => {
if (typeof result === 'function') {
this.once('stop core', result)
}
})
this.emit((this._status = 'core started')) this.emit((this._status = 'core started'))
} }

View File

@@ -22,7 +22,6 @@
"@vates/event-listeners-manager": "^1.0.1", "@vates/event-listeners-manager": "^1.0.1",
"@vates/parse-duration": "^0.1.1", "@vates/parse-duration": "^0.1.1",
"@vates/task": "^0.0.1", "@vates/task": "^0.0.1",
"@xen-orchestra/emit-async": "^1.0.0",
"@xen-orchestra/log": "^0.6.0", "@xen-orchestra/log": "^0.6.0",
"acme-client": "^5.0.0", "acme-client": "^5.0.0",
"app-conf": "^2.3.0", "app-conf": "^2.3.0",

View File

@@ -38,6 +38,7 @@
- @vates/read-chunk patch - @vates/read-chunk patch
- @vates/stream-reader minor - @vates/stream-reader minor
- @xen-orchestra/backups minor - @xen-orchestra/backups minor
- @xen-orchestra/mixins minor
- vhd-lib minor - vhd-lib minor
- xo-web patch - xo-web patch
- xo-server minor - xo-server minor