refactor(cli): dispose bootstrap instance explicitly (#27721)
This commit is contained in:
parent
727a83aa7a
commit
bf64f8cbb5
2 changed files with 31 additions and 14 deletions
|
|
@ -1,17 +1,11 @@
|
||||||
import { Instance } from "../project/instance"
|
|
||||||
import { InstanceRuntime } from "../project/instance-runtime"
|
import { InstanceRuntime } from "../project/instance-runtime"
|
||||||
import { WithInstance } from "../project/with-instance"
|
import { context } from "../project/instance-context"
|
||||||
|
|
||||||
export async function bootstrap<T>(directory: string, cb: () => Promise<T>) {
|
export async function bootstrap<T>(directory: string, cb: () => Promise<T>) {
|
||||||
return WithInstance.provide({
|
const ctx = await InstanceRuntime.load({ directory })
|
||||||
directory,
|
try {
|
||||||
fn: async () => {
|
return await context.provide(ctx, cb)
|
||||||
try {
|
} finally {
|
||||||
const result = await cb()
|
await InstanceRuntime.disposeInstance(ctx)
|
||||||
return result
|
}
|
||||||
} finally {
|
|
||||||
await InstanceRuntime.disposeInstance(Instance.current)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,13 @@ import { existsSync } from "node:fs"
|
||||||
import path from "node:path"
|
import path from "node:path"
|
||||||
import { pathToFileURL } from "node:url"
|
import { pathToFileURL } from "node:url"
|
||||||
import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
|
import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
|
||||||
import { Effect, Layer } from "effect"
|
import { Cause, Effect, Exit, Fiber, Layer } from "effect"
|
||||||
import { bootstrap as cliBootstrap } from "../../src/cli/bootstrap"
|
import { bootstrap as cliBootstrap } from "../../src/cli/bootstrap"
|
||||||
import { InstanceLayer } from "../../src/project/instance-layer"
|
import { InstanceLayer } from "../../src/project/instance-layer"
|
||||||
import { InstanceStore } from "../../src/project/instance-store"
|
import { InstanceStore } from "../../src/project/instance-store"
|
||||||
import { disposeAllInstances, tmpdirScoped } from "../fixture/fixture"
|
import { disposeAllInstances, tmpdirScoped } from "../fixture/fixture"
|
||||||
import { testEffect } from "../lib/effect"
|
import { testEffect } from "../lib/effect"
|
||||||
|
import { waitGlobalBusEvent } from "../server/global-bus"
|
||||||
|
|
||||||
const it = testEffect(Layer.mergeAll(InstanceLayer.layer, CrossSpawnSpawner.defaultLayer))
|
const it = testEffect(Layer.mergeAll(InstanceLayer.layer, CrossSpawnSpawner.defaultLayer))
|
||||||
|
|
||||||
|
|
@ -54,6 +55,13 @@ const bootstrapFixture = Effect.gen(function* () {
|
||||||
return { directory: dir, marker }
|
return { directory: dir, marker }
|
||||||
})
|
})
|
||||||
|
|
||||||
|
function waitDisposed(directory: string) {
|
||||||
|
return waitGlobalBusEvent({
|
||||||
|
message: "timed out waiting for CLI bootstrap instance disposal",
|
||||||
|
predicate: (event) => event.payload.type === "server.instance.disposed" && event.directory === directory,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
it.live("InstanceStore.provide runs InstanceBootstrap before effect", () =>
|
it.live("InstanceStore.provide runs InstanceBootstrap before effect", () =>
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const tmp = yield* bootstrapFixture
|
const tmp = yield* bootstrapFixture
|
||||||
|
|
@ -75,6 +83,21 @@ it.live("CLI bootstrap runs InstanceBootstrap before callback", () =>
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
it.live("CLI bootstrap disposes the instance when the callback rejects", () =>
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const tmp = yield* bootstrapFixture
|
||||||
|
const disposed = yield* waitDisposed(tmp.directory).pipe(Effect.forkScoped)
|
||||||
|
|
||||||
|
const exit = yield* Effect.promise(() => cliBootstrap(tmp.directory, async () => Promise.reject(new Error("boom")))).pipe(
|
||||||
|
Effect.exit,
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(Exit.isFailure(exit)).toBe(true)
|
||||||
|
if (Exit.isFailure(exit)) expect(Cause.squash(exit.cause)).toMatchObject({ message: "boom" })
|
||||||
|
yield* Fiber.join(disposed)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
it.live("InstanceStore.reload runs InstanceBootstrap", () =>
|
it.live("InstanceStore.reload runs InstanceBootstrap", () =>
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const tmp = yield* bootstrapFixture
|
const tmp = yield* bootstrapFixture
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue