fix(agent): close proxy ingest upload per batch so events stream live#3043
Merged
Conversation
2 tasks
Contributor
|
Reviews (1): Last reviewed commit: "close ingest upload after each drained b..." | Re-trigger Greptile |
3e40b24 to
3623e13
Compare
|
React Doctor found no issues in the changed files. 🎉 Reviewed by React Doctor for commit |
Contributor
|
Reviews (2): Last reviewed commit: "close ingest upload after each drained b..." | Re-trigger Greptile |
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.
Problem
Cloud task runs stream agent output to the browser through the agent-proxy: the sandbox POSTs events to the proxy ingest endpoint (write leg), the proxy writes them to a Redis stream, and the browser consumes them over SSE (read leg). The read leg works, but live output never showed up on the proxy write leg — the browser sat on keepalives and then received the whole turn in one burst (or on refresh from persisted history).
Root cause is the write leg's transport. The ingest sender streams events into a single long-lived chunked
POSTthat stays open until the stream window rolls. The ingress in front of the proxy buffers the request body and only forwards it once the request closes, so the proxy receives nothing until the upload rolls. Streaming a response (SSE) is well supported; dribbling bytes into a long-lived request body is not — intermediaries buffer it. The tell: the empty bounded sequence-sync probe always arrives immediately, while the long-lived content upload doesn't land until it closes.Changes
After a flush drains the buffer, close the active upload instead of holding it open, gated to the proxy write leg (
usingProxy). Each drained batch now rides its own promptly-closed request, so a buffering ingress forwards it within a round-trip and delivery is effectively live. Sequencing, backpressure, 409 rebase and restart-resume are unchanged — only the moment we close the upload moved.This supersedes the short-window stopgap from #3042: per-batch close makes a shortened proxy window redundant (the upload closes per batch, so a window never trips), so
DEFAULT_PROXY_STREAM_WINDOW_MSis removed and the window default is a single value again.Scope is limited to the proxy path on purpose:
usingProxy): close per batch → live delivery.drainForStop(that path runs understopped, where the new close is skipped).How did you test this?
I'm an agent (Claude Code), human-directed. Automated tests I actually ran, all green:
vitest run src/server/event-stream-sender.test.ts(17 pass). Replaced the old "keeps the active ingest request open across scheduled flushes" case — that held-open behavior was the bug — with "closes the active ingest upload after each drained batch on the proxy path", which drives the proxy path and asserts each batch is delivered and closed beforestop()while the completion line rides a final upload. The Django-path cases (noeventIngestBaseUrl) are unchanged and still pass, confirming the gate.tsc --noEmitandbiome checkon the changed files — clean.I did not run a full sandbox-to-browser flow in a live environment.
Automatic notifications