Skip to content

Commit fbca295

Browse files
fix(opencode): bound owned reconnects that cannot restart the server
An owned server that could not restart was borrowed again forever: the reconnect retry around borrow had no attempt limit, and borrow failures never count as permanent. Reconnects are bounded to five attempts again, as on main; only reconcile against a live owned process keeps waiting. AI-assisted; verified with the tests and tools listed above.
1 parent 0239c8b commit fbca295

2 files changed

Lines changed: 11 additions & 8 deletions

File tree

‎apps/server/src/orchestration-v2/Adapters/OpenCode2AdapterV2.test.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4427,7 +4427,7 @@ it.layer(McpProviderSessions.layer)("OpenCode2 adapter", (it) => {
44274427
event("session.execution.succeeded", { sessionID: SESSION }),
44284428
{ type: "runtime_exit", status: "success" },
44294429
],
4430-
{ borrowers, external: true },
4430+
{ borrowers },
44314431
);
44324432
const events = yield* runtime.events.pipe(Stream.runCollect, Effect.forkScoped);
44334433
yield* runtime.startTurn(withLineage(thread));

‎packages/provider-opencode/src/server/v2/adapter.ts‎

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3667,8 +3667,8 @@ export const make = Effect.fn("OpenCode2Adapter.make")(function* (instanceId: Pr
36673667
for (const state of threads.values()) {
36683668
yield* recoverShells(state).pipe(Effect.ignore({ log: true }));
36693669
}
3670-
// An owned process's exit, rather than a read deadline, bounds recovery; the retry then
3671-
// borrows a restarted server. HTTP waits stay outside the event lock so Stop can still settle.
3670+
// An owned process's exit, rather than a read deadline, bounds recovery; the bounded retry
3671+
// below then borrows a restarted server. HTTP waits stay outside the event lock so Stop can still settle.
36723672
const exited = next.processExit;
36733673
yield* exited === undefined
36743674
? reconcile().pipe(Effect.timeout(RECONCILE_TIMEOUT))
@@ -3680,11 +3680,14 @@ export const make = Effect.fn("OpenCode2Adapter.make")(function* (instanceId: Pr
36803680
);
36813681
return stream;
36823682
}).pipe(
3683-
Effect.retry(
3684-
connection.processExit === undefined
3685-
? { times: RECONNECT_ATTEMPTS - 1, schedule: Schedule.spaced(RECONNECT_DELAY) }
3686-
: OWNED_RECOVERY_RETRY,
3687-
),
3683+
// Borrows and process exits stay bounded; only a live owned process is waited on above.
3684+
Effect.retry({
3685+
times: RECONNECT_ATTEMPTS - 1,
3686+
schedule: Schedule.spaced(RECONNECT_DELAY),
3687+
...(connection.processExit === undefined
3688+
? {}
3689+
: { while: (error: unknown) => !isPermanentRecoveryError(error) }),
3690+
}),
36883691
);
36893692

36903693
let currentScope = initial.scope;

0 commit comments

Comments
 (0)