Repository navigation
[api] Answer nested requests on the sync connection in stack order - #64639
Jake Bailey (jakebailey) merged 2 commits into
Conversation
There was a problem hiding this comment.
Copilot review overview
🔵 Needs a closer look
The bidirectional synchronization and panic-recovery behavior warrant final human review despite no concrete blocking findings.
Review effort: Balanced
Findings: None
What changed in this PR
Fixes #64631 by coordinating synchronous IPC exchanges in stack order so overlapping callbacks receive the correct responses.
Changes:
- Tracks in-flight exchanges and waits before starting calls or answering requests.
- Adds regression tests for nested response ordering and response-write panic handling.
| File | Description |
|---|---|
tsc/internal/ipc/conn_sync.go |
Adds stack-based coordination for calls and responses. |
tsc/internal/ipc/conn_sync_test.go |
Tests overlapping nested requests and panic propagation. |
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
Andrew Branch (andrewbranch)
left a comment
There was a problem hiding this comment.
I think this is correct and I don't see a simpler way to do it, but Jake Bailey (@jakebailey) has talked me out of using a sync.Cond before, so he may want to take a look.
|
Yeah, I blindly assigned this to you, but now that I look, I suspect there's a better design here |
|
I had tried to think about blocking "unrelated" client callbacks until the current request stack is clear, but it turns out it's kind of hard to determine what's "unrelated" vs. what's truly reentrant here. I think you could do something with context plumbing, but I think that would end up being a lot more complicated. |
|
Jake Bailey (@jakebailey) Andrew Branch (@andrewbranch) thanks both, I pushed a smaller version.
|
Jake Bailey (jakebailey)
left a comment
There was a problem hiding this comment.
With the latest push, I think this is fine.
While
SyncConn.Callhandles a nested request from a client callback, it releases its lock, so another goroutine's call can start inside the client's pending nested request. Responses are matched by method name, so the nested answer and both callback answers then reach the wrong requests.Impact: a resolver callback that delegates to another resolver, the pattern the API's own test shows, binds most imports to the wrong module once the loader uses more than one thread. Every type and diagnostic the tool reads from that program is then wrong, and no error says so. In the reproduction, 873 of 900 nested answers went to another request.
The sync connection now answers exchanges in the order a synchronous client can handle them. It counts the calls in flight and records whether the innermost one is reading its response. A new call waits while one is reading. A message the client sends from inside a callback clears that flag, so the handler's own calls go through, and the call that received it reads again only once every call made above it has returned. A request is answered at the same point, which is what keeps nested answers from crossing.
TestSyncConnAnswersNestedRequestsInStackOrderdrives two overlapping callbacks against a fake synchronous client undertesting/synctest. It fails on each of 20 runs without the change.TestSyncConnNotificationHandlerCanCallkeeps a call made from a notification handler working, as it does onmain. With atscbuilt from this branch, the reproduction in the issue gives 900 right answers of 900.I met this while building deadset-ts, the TypeScript analyzer of deadset, on the TypeScript 7 API, as part of a small set of defects that work hit, which is why there are a few related reports from me.
An AI coding agent wrote this patch. I have read, built and tested it and will handle the review.
Backlogmilestone (required)mainbranchnpx hereby testnpx hereby lintnpx hereby check:formatFixes #64631