Skip to content

Commit 67ccc45

Browse files
AndyS77zai-glm-52
andcommitted
fix(config): add failExecution, prune states map, fix onBusy ordering
- Reset reloadInFlight/blockers/reloadInput on store.reload failure via failExecution helper, emit Done event so clients recover - Prune completed State entries from states Map to avoid unbounded growth - Move onBusy after Deferred.make in runner.ts so a throwing onBusy doesn't leave the session stuck in active state Co-Authored-By: zai-glm-52 <[email protected]> Agent: @bug-fix Scope: #43458
1 parent 68a7ad2 commit 67ccc45

2 files changed

Lines changed: 30 additions & 7 deletions

File tree

‎packages/opencode/src/config/reload.ts‎

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ export interface Interface {
6868
export class Service extends Context.Service<Service, Interface>()("@opencode/ConfigReload") {}
6969

7070
type State = {
71+
key: string
7172
pending: boolean
7273
reloadInFlight: boolean
7374
reloadInput?: InstanceStore.LoadInput
@@ -107,7 +108,7 @@ export const layer = Layer.effect(
107108
const state = yield* currentState(states)
108109
state.active.delete(sessionID)
109110
yield* Effect.logDebug("config reload session finished current turn", { sessionID })
110-
yield* continueOrDone(state, store, events, resume)
111+
yield* continueOrDone(state, states, store, events, resume)
111112
})
112113

113114
const getBootstrapCycle = Effect.fn("ConfigReload.getBootstrapCycle")(function* () {
@@ -128,7 +129,7 @@ export const layer = Layer.effect(
128129
const state = yield* currentState(states)
129130
state.blockers.delete(blockerID)
130131
yield* Effect.logDebug("config reload blocker released", { blockerID })
131-
yield* continueOrDone(state, store, events, resume)
132+
yield* continueOrDone(state, states, store, events, resume)
132133
})
133134

134135
const completeBootstrap = Effect.fn("ConfigReload.completeBootstrap")(function* (cycle: number) {
@@ -137,7 +138,7 @@ export const layer = Layer.effect(
137138
if (!state) return false
138139
state.blockers.delete("tui-bootstrap")
139140
yield* Effect.logDebug("config reload bootstrap completed", { cycle })
140-
yield* continueOrDone(state, store, events, resume)
141+
yield* continueOrDone(state, states, store, events, resume)
141142
return true
142143
})
143144

@@ -148,7 +149,7 @@ export const layer = Layer.effect(
148149
if (!state) return false
149150
state.blockers.delete("tui-bootstrap")
150151
yield* Effect.logDebug("config reload bootstrap completed", { cycle: input.cycle })
151-
yield* continueOrDone(state, store, events, resume)
152+
yield* continueOrDone(state, states, store, events, resume)
152153
return true
153154
})
154155

@@ -167,7 +168,10 @@ export const layer = Layer.effect(
167168
const execution = yield* prepareExecution(state, current.input, events)
168169
yield* store.reload(execution.input).pipe(
169170
Effect.catchCause((cause) =>
170-
Effect.logError("config reload store.reload failed", { cause: String(cause) }),
171+
Effect.gen(function* () {
172+
yield* Effect.logError("config reload store.reload failed", { cause: String(cause) })
173+
yield* failExecution(state, events)
174+
}),
171175
),
172176
)
173177
return {
@@ -236,6 +240,7 @@ function getState(states: Map<string, State>, key: string) {
236240
const existing = states.get(key)
237241
if (existing) return existing
238242
const state: State = {
243+
key,
239244
pending: false,
240245
reloadInFlight: false,
241246
bootstrapCycle: 0,
@@ -301,14 +306,29 @@ function executePending(
301306
const execution = yield* prepareExecution(state, input, events)
302307
yield* store.reload(execution.input).pipe(
303308
Effect.catchCause((cause) =>
304-
Effect.logError("config reload store.reload failed", { cause: String(cause) }),
309+
Effect.gen(function* () {
310+
yield* Effect.logError("config reload store.reload failed", { cause: String(cause) })
311+
yield* failExecution(state, events)
312+
}),
305313
),
306314
)
307315
})
308316
}
309317

318+
function failExecution(state: State, events: EventV2.Interface) {
319+
return Effect.gen(function* () {
320+
state.reloadInFlight = false
321+
state.pending = false
322+
state.blockers.clear()
323+
state.reloadInput = undefined
324+
state.resumeSessionID = undefined
325+
yield* publish(events, Event.Done, {})
326+
})
327+
}
328+
310329
function continueOrDone(
311330
state: State,
331+
states: Map<string, State>,
312332
store: InstanceStore.Interface,
313333
events: EventV2.Interface,
314334
resume: ResumeFn,
@@ -331,6 +351,9 @@ function continueOrDone(
331351
state.resumeSessionID = undefined
332352
yield* resume(sessionID)
333353
}
354+
if (!isBlocked(state) && !state.pending && !state.reloadInFlight) {
355+
states.delete(state.key)
356+
}
334357
})
335358
}
336359
function publish<Definition extends EventV2.Definition>(

‎packages/opencode/src/effect/runner.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,8 @@ export const make = <A, E = never>(
129129
return [awaitDone(run.done), { _tag: "ShellThenRun", shell: st.shell, run }] as const
130130
}
131131
case "Idle": {
132-
yield* onBusy
133132
const done = yield* Deferred.make<A, E | Cancelled>()
133+
yield* onBusy
134134
const run = yield* startRun(work, done)
135135
return [awaitDone(done), { _tag: "Running", run }] as const
136136
}

0 commit comments

Comments
 (0)