fix(server): OpenCode stop no longer hangs when a turn is interrupted before submission - #12003
SunkenInTime wants to merge 1 commit into
Conversation
… before submission Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
ApprovabilityVerdict: Approved at Macroscope's review found this PR approvable — This is a small, self-contained server bug fix that settles the pending OpenCode admission during interrupted turns, preventing teardown hangs. A targeted regression test covers the race, with no product-default, schema, deployment, security, or static-analysis changes. You can add or adjust custom eligibility rules. Learn more. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (2)
Included review availability: Your plan provides up to 10 included reviews per hour; 7 remain after this review. 📝 WalkthroughWalkthrough
ChangesOpenCode shutdown
Priority: ➖ Normal Estimated code review effort: 2 (Simple) | ~10 minutes Change: Bug fix · Severity of issue fixed: Medium Suggested reviewers: Merge Risk: ⚪ Minimal · up to No concrete merge-blocking risk remains; the interrupted-send shutdown fix is mergeable after normal checks. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
|
Note: GPT-6 on behalf of shivam (@shivamhwp). This fixes the interrupted-send cancellation race behind #11889. The remaining gap is that Could we make that wait specific to the thread being created? Reusing the same thread ID should still wait for its previous cleanup, while unrelated chats should proceed. Add regression coverage for both behaviors. This could be a separate follow-up PR to keep your cancellation fix focused. |
Fixes #11889
What Changed
OpenCodeAdapter.sendTurnnow settlespromptAdmission.submissionSettledin anEffect.ensuringfinalizer on the admission body, so the deferred resolves no matter how the body exits.Test:
stopSession completes after sendTurn is interrupted before the prompt is submittedgates theClocksosendTurnis parked right after it publishes the admission (inupdateProviderSession'snowIso), interrupts it there, then assertsstopSessionfinishes and the session is gone. It hangs indefinitely without the fix and passes with it.Why
sendTurnpublishescontext.promptAdmissionand only settlessubmissionSettledlater — at the early-cancel check or in the forked prompt fiber'sonExit. Between those points there are yield points (updateProviderSession,emit). If the caller fiber is interrupted in that window (e.g. the turn start is torn down while a thread is being deleted), the deferred is never settled.stopSession→stopOpenCodeContext→cancelPendingOpenCodePromptthen waits on it forever.That hang sits inside the thread-deletion worker.
ws.tsfences everythread.createonThreadDeletionReactor.drainThrough, so one stuck OpenCode teardown stops every new chat until the server restarts — the symptom reported in #11889. Settling the deferred on every exit path is the smallest change that removes the pin; the deletion fence itself is left as designed.Reproduce
This is a fiber-interruption race, so there is no deterministic UI or screenshot repro. The regression test is the reproduction:
main, apply only the test from this PR.vp test run apps/server/src/provider/Layers/OpenCodeAdapter.test.ts -t "interrupted before the prompt is submitted"— the test never completes (stopSessionblocks onsubmissionSettled).111 passed).In-app the symptom is: delete an OpenCode thread whose turn was being started, then every subsequent "New chat" spins until restart.
UI Changes
Not applicable (server-only; no deterministic UI reproduction).
Checklist
Verified with
vp test run apps/server/src/provider/Layers/OpenCodeAdapter.test.ts(111 passed), servertsc --noEmit, andvp linton the two touched files.Written by Claude (Devin harness).
Summary by CodeRabbit
Bug Fixes
Tests