Centralize response in server and ensure response for transactional requests#3457
Open
kenhuuu wants to merge 2 commits into
Open
Centralize response in server and ensure response for transactional requests#3457kenhuuu wants to merge 2 commits into
kenhuuu wants to merge 2 commits into
Conversation
Introduce a per-request HttpResponseCoordinator that is the sole owner of
response writes for the HTTP endpoint, guarded by a single monitor. It replaces
three uncoordinated state holders (Context.requestState, Context.startedResponse,
StateKey.HTTP_RESPONSE_SENT) with one {NOT_STARTED, STREAMING, COMPLETED} state
machine, closing the timeout-vs-eval double-response race: whichever thread
terminates the response first wins and the others no-op via the COMPLETED
short-circuit.
Assisted-by: Claude Code:claude-opus-4-8
Makes sure that if a traversal closes the transaction that all subsequent requests meant for that transaction receive a 404 and aren't left waiting for a response. Assisted-by: Claude Code:claude-opus-4-8
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Response writing in the 4.x HTTP endpoint was coordinated through three uncoordinated state holders (
Context.requestState,Context.startedResponse,StateKey.HTTP_RESPONSE_SENT) touched by two threads (eval worker + timeout scheduler) with no happens-before relationship. The non-atomic check-then-act guards allowed a double-response race under timeout and an unterminated chunked stream (which hangs the client and poisons thekeep-alive channel). Write logic was also scattered across
makeChunkandHttpHandlerUtil, so "who writes, in what order" was an unwritten contract.What changed
A single per-request
HttpResponseCoordinatoris now the sole owner of response writes, guarded by one monitor with a 3-state machine (NOT_STARTED → STREAMING → COMPLETED). This makes the key invariant — exactly one well-formed, terminated response — true by construction:COMPLETEDfirst wins, the other no-ops. No more check-then-act gap.complete()is idempotent and called from afinally, so the terminal chunk is always written.The three state holders,
makeChunk, and theHttpHandlerUtilwrite helpers are removed/absorbed (sendErrorstays for the pre-evaluation rejection path). Backpressure stays outside the lock, so there's no deadlock surface.This is a pure internal refactor: wire output is byte-identical, no public/driver API or status-code changes.
Second fix: enqueued transactions must return errors
Validating the refactor surfaced an intermittent CI hang. Transactions run on a single-threaded executor; a request queued behind a
commitwas silently discarded byshutdownNow(), so its client never got a response. Fixed inUnmanagedTransaction.closeby using a gracefulshutdown()(queued tasks run and return 404 instead of vanishing) and removing the transaction from the manager before shutdown so those tasks fail fast without mutating a closed transaction. The ordering is documented as load-bearing.NOTE: No documentation or CHANGELOG as this is just a refactoring.
VOTE+1