fix(e2b): await teardown and honor published status

This commit is contained in:
Tianyi Cui
2026-07-29 10:14:06 +08:00
parent d0648446c9
commit 896bcd64a1
3 changed files with 54 additions and 5 deletions

View File

@@ -547,6 +547,20 @@ describe('E2BSubprocessHandle', () => {
await expect(handle.waitForExit()).resolves.toBe(true)
})
it('preserves a published nonzero exit code when termination settles the SDK inside the drain grace', async () => {
const fake = new FakeSandbox()
const handle = new E2BSubprocessHandle(runtime(fake), spec({ graceMs: 100 }), '/runtime/drain-signal-settled')
await flush()
fake.exitStatus = '7\n'
fake.afterStatusRead = () => {
fake.afterStatusRead = undefined
handle.terminate()
}
await expect(handle.done).resolves.toEqual({ exitCode: 7, signal: null })
await expect(handle.waitForExit()).resolves.toBe(true)
})
it('rejects an invalid direct-command exit status', async () => {
const fake = new FakeSandbox()
const handle = new E2BSubprocessHandle(runtime(fake), spec(), '/runtime/invalid-status')
@@ -1336,6 +1350,35 @@ describe('E2BSubprocessService', () => {
await expect(handle.done).resolves.toEqual({ exitCode: null, signal: 'SIGTERM' })
})
it('waits for every owned cleanup before reporting a disposal failure', async () => {
const { ctx, fiber } = await service()
const failed = {
terminate: vi.fn(),
waitForExit: vi.fn(async () => { throw new Error('cleanup failed') }),
done: Promise.resolve({ exitCode: 0, signal: null }),
} as unknown as E2BSubprocessHandle
let finishCleanup!: () => void
const cleanup = new Promise<boolean>((resolve) => {
finishCleanup = () => { resolve(true) }
})
const draining = {
terminate: vi.fn(),
waitForExit: vi.fn(() => cleanup),
done: Promise.resolve({ exitCode: 0, signal: null }),
} as unknown as E2BSubprocessHandle
const live = (ctx.subprocess as unknown as { live: Set<E2BSubprocessHandle> }).live
live.add(failed)
live.add(draining)
let disposed = false
const disposing = fiber.dispose().then(() => { disposed = true })
await flush()
expect(disposed).toBe(false)
finishCleanup()
await disposing
expect(live).toEqual(new Set([failed]))
})
it('releases naturally settled handles before later service disposal', async () => {
const fake = new FakeSandbox()
const { ctx, fiber } = await service(fake)