fix(app-boot): await only failed activation fibers
This commit is contained in:
@@ -229,6 +229,7 @@ export function assertEntriesLoaded(ctx: Context, binName: string): void {
|
||||
*/
|
||||
const FIBER_PENDING = 0 as FiberState.PENDING
|
||||
const FIBER_ACTIVE = 2 as FiberState.ACTIVE
|
||||
const FIBER_FAILED = 3 as FiberState.FAILED
|
||||
|
||||
/** Render a thrown plugin value without discarding an Error's original stack. */
|
||||
function formatActivationError(error: unknown): string {
|
||||
@@ -238,7 +239,9 @@ function formatActivationError(error: unknown): string {
|
||||
/**
|
||||
* Reject a settled Loader tree when an enabled entry failed or remains inactive.
|
||||
* Plugin failures include the original thrown stack; pending entries name their
|
||||
* unresolved services because no plugin error exists for that state.
|
||||
* unresolved services because no plugin error exists for that state. Active
|
||||
* entries require no further wait; only failed fibers are awaited to recover
|
||||
* their private rejection reason.
|
||||
* @param ctx - the settled context whose Loader entries to audit.
|
||||
* @param binName - the diagnostic prefix on the thrown error.
|
||||
* @returns nothing when every enabled entry is active.
|
||||
@@ -252,15 +255,17 @@ export async function assertEntriesActivated(ctx: Context, binName: string): Pro
|
||||
for (const entry of ctx.loader.entries()) {
|
||||
const fiber = entry.fiber
|
||||
if (fiber === undefined || entry.disabled) continue
|
||||
try {
|
||||
await fiber.await()
|
||||
} catch (error) {
|
||||
rejectionReasons.push(error)
|
||||
failures.push(`${entry.options.name}: ${formatActivationError(error)}`)
|
||||
continue
|
||||
}
|
||||
const state = fiber.state
|
||||
if (state === FIBER_ACTIVE) continue
|
||||
if (state === FIBER_FAILED) {
|
||||
try {
|
||||
await fiber.await()
|
||||
} catch (error) {
|
||||
rejectionReasons.push(error)
|
||||
failures.push(`${entry.options.name}: ${formatActivationError(error)}`)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if (state === FIBER_PENDING) {
|
||||
const missing = Object.keys(fiber.inject).filter(service => fiber.ctx.get(service) === undefined)
|
||||
const subject = missing.length === 1 ? 'service' : 'services'
|
||||
|
||||
@@ -209,10 +209,22 @@ describe('assertEntriesActivated', () => {
|
||||
})
|
||||
|
||||
it('passes active entries and ignores disabled entries', async () => {
|
||||
let awaitCalls = 0
|
||||
const active = fiber(2)
|
||||
active.await = async () => {
|
||||
awaitCalls++
|
||||
return undefined
|
||||
}
|
||||
const disabled = fiber(3, new Error('disabled failure'))
|
||||
disabled.await = async () => {
|
||||
awaitCalls++
|
||||
throw new Error('disabled failure')
|
||||
}
|
||||
await expect(assertEntriesActivated(ctxWith([
|
||||
{ fiber: fiber(2), options: { name: 'active' } },
|
||||
{ disabled: true, options: { name: 'disabled' } },
|
||||
{ fiber: active, options: { name: 'active' } },
|
||||
{ fiber: disabled, disabled: true, options: { name: 'disabled' } },
|
||||
]), NAME)).resolves.toBeUndefined()
|
||||
expect(awaitCalls).toBe(0)
|
||||
})
|
||||
|
||||
it('reports the plugin name and original activation stack instead of fiber state 3', async () => {
|
||||
@@ -232,17 +244,28 @@ describe('assertEntriesActivated', () => {
|
||||
})
|
||||
|
||||
it('reports unresolved services for pending entries', async () => {
|
||||
let awaitCalls = 0
|
||||
const expected = [
|
||||
`${NAME}: 3 entries did not activate`,
|
||||
'waiting: pending (waiting for services: missingA, missingB)',
|
||||
'single-wait: pending (waiting for service: missing)',
|
||||
'unknown-wait: pending (waiting for services: unknown)',
|
||||
].join('\n')
|
||||
const waiting = fiber(0, undefined, { ready: {}, missingA: {}, missingB: {} }, ['ready'])
|
||||
const singleWait = fiber(0, undefined, { missing: {} })
|
||||
const unknownWait = fiber(0)
|
||||
for (const item of [waiting, singleWait, unknownWait]) {
|
||||
item.await = async () => {
|
||||
awaitCalls++
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
await expect(assertEntriesActivated(ctxWith([
|
||||
{ fiber: fiber(0, undefined, { ready: {}, missingA: {}, missingB: {} }, ['ready']), options: { name: 'waiting' } },
|
||||
{ fiber: fiber(0, undefined, { missing: {} }), options: { name: 'single-wait' } },
|
||||
{ fiber: fiber(0), options: { name: 'unknown-wait' } },
|
||||
{ fiber: waiting, options: { name: 'waiting' } },
|
||||
{ fiber: singleWait, options: { name: 'single-wait' } },
|
||||
{ fiber: unknownWait, options: { name: 'unknown-wait' } },
|
||||
]), NAME)).rejects.toThrow(expected)
|
||||
expect(awaitCalls).toBe(0)
|
||||
})
|
||||
|
||||
it('retains the numeric diagnostic for a settled unexpected state', async () => {
|
||||
|
||||
Reference in New Issue
Block a user