diff --git a/packages/subprocess/subprocess-local/src/index.ts b/packages/subprocess/subprocess-local/src/index.ts index 68e781b2af..751653e8e8 100644 --- a/packages/subprocess/subprocess-local/src/index.ts +++ b/packages/subprocess/subprocess-local/src/index.ts @@ -48,7 +48,7 @@ export class LocalSubprocessService extends SubprocessService { super(ctx) ctx.effect(() => { const onHostExit = (): void => { this.terminateForHostExit() } - process.on('exit', onHostExit) + process.prependListener('exit', onHostExit) return async () => { try { await this.disposeManagedProcesses() diff --git a/packages/subprocess/subprocess-local/tests/local.spec.ts b/packages/subprocess/subprocess-local/tests/local.spec.ts index 22affc50e0..412f55a49c 100644 --- a/packages/subprocess/subprocess-local/tests/local.spec.ts +++ b/packages/subprocess/subprocess-local/tests/local.spec.ts @@ -21,6 +21,23 @@ function spec(command: string, overrides: Partial = {}): Su } describe('LocalSubprocessService', () => { + it('places the host-exit finalizer before listeners that predate the service', async () => { + const baseline = new Set(process.listeners('exit')) + const prior = vi.fn() + process.on('exit', prior) + const ctx = new Context() + const fiber = await ctx.plugin(LocalSubprocessService) + try { + const listeners = process.listeners('exit') + const finalizer = listeners.find(candidate => !baseline.has(candidate) && candidate !== prior) + expect(finalizer).toBeTypeOf('function') + expect(listeners.indexOf(finalizer!)).toBeLessThan(listeners.indexOf(prior)) + } finally { + process.off('exit', prior) + await fiber.dispose() + } + }) + it('keeps the host-exit finalizer active until normal disposal reaches quiescence', async () => { const before = new Set(process.listeners('exit')) const ctx = new Context()