mirror of
https://github.com/anomalyco/opencode.git
synced 2026-07-10 08:58:27 +00:00
fix(core): batch plugin shutdown
This commit is contained in:
parent
79b55d4db8
commit
cf31029350
2 changed files with 45 additions and 3 deletions
|
|
@ -103,8 +103,16 @@ export const layer = Layer.effect(
|
|||
}
|
||||
}[keyof Hooks][] = []
|
||||
const events = yield* EventV2.Service
|
||||
const scope = yield* Scope.Scope
|
||||
const locks = KeyedMutex.makeUnsafe<ID>()
|
||||
const scope = yield* Scope.make()
|
||||
|
||||
// One registry-owned scope lets shutdown remove every plugin transform in one batch.
|
||||
yield* Effect.addFinalizer((exit) =>
|
||||
Effect.gen(function* () {
|
||||
hooks = []
|
||||
yield* State.batch(Scope.close(scope, exit))
|
||||
}),
|
||||
)
|
||||
|
||||
const svc = Service.of({
|
||||
add: Effect.fn("Plugin.add")(function* (input) {
|
||||
|
|
@ -112,7 +120,7 @@ export const layer = Layer.effect(
|
|||
yield* locks.withLock(id)(
|
||||
Effect.gen(function* () {
|
||||
const existing = hooks.find((item) => item.id === id)
|
||||
if (existing) yield* Scope.close(existing.scope, Exit.void).pipe(Effect.ignore)
|
||||
if (existing) yield* State.batch(Scope.close(existing.scope, Exit.void)).pipe(Effect.ignore)
|
||||
const childScope = yield* Scope.fork(scope)
|
||||
const result = yield* input.effect.pipe(
|
||||
Scope.provide(childScope),
|
||||
|
|
@ -181,7 +189,7 @@ export const layer = Layer.effect(
|
|||
Effect.gen(function* () {
|
||||
const existing = hooks.find((item) => item.id === id)
|
||||
hooks = hooks.filter((item) => item.id !== id)
|
||||
if (existing) yield* Scope.close(existing.scope, Exit.void).pipe(Effect.ignore)
|
||||
if (existing) yield* State.batch(Scope.close(existing.scope, Exit.void)).pipe(Effect.ignore)
|
||||
}),
|
||||
)
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -46,6 +46,40 @@ describe("PluginV2", () => {
|
|||
}),
|
||||
)
|
||||
|
||||
it.effect("batches plugin state rebuilds when the registry layer finalizes", () =>
|
||||
Effect.gen(function* () {
|
||||
let finalized = 0
|
||||
const values = State.create({
|
||||
initial: () => ({ values: [] as string[] }),
|
||||
draft: (draft) => ({ add: (value: string) => draft.values.push(value) }),
|
||||
finalize: () => Effect.sync(() => finalized++),
|
||||
})
|
||||
const layerScope = yield* Scope.fork(yield* Scope.Scope)
|
||||
const plugin = Context.get(yield* Layer.buildWithScope(Layer.fresh(plugins), layerScope), PluginV2.Service)
|
||||
|
||||
yield* State.batch(
|
||||
Effect.forEach(
|
||||
["first", "second"],
|
||||
(id) =>
|
||||
plugin.add({
|
||||
id: PluginV2.ID.make(id),
|
||||
effect: values
|
||||
.transform((editor) => {
|
||||
editor.add(id)
|
||||
})
|
||||
.pipe(Effect.asVoid),
|
||||
}),
|
||||
{ discard: true },
|
||||
),
|
||||
)
|
||||
finalized = 0
|
||||
|
||||
yield* Scope.close(layerScope, Exit.void)
|
||||
expect(values.get().values).toEqual([])
|
||||
expect(finalized).toBe(1)
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("serializes same-ID additions and leaves one removable attachment", () =>
|
||||
Effect.gen(function* () {
|
||||
const values = state()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue