Skip to content

fix(qoder): bound ensureMeaningfulUpstream after 200 (#344) - #345

Merged
caigee-cmd merged 2 commits into
mainfrom
fix/qoder-pat-meaningful-upstream-timeout
Oct 22, 2026
Merged

caigee-cmd merged 2 commits into
mainfrom
fix/qoder-pat-meaningful-upstream-timeout

Conversation

@caigee-cmd

Copy link
Copy Markdown
Owner

Summary

Fixes #344

Qoder PAT in-process ChatStream used doWithFirstByteTimeout only until response headers. After a 200, ensureMeaningfulUpstream looped br.ReadString('\n') with no deadline, so a heartbeat-only SSE stream hung the client forever (no request_stream_diagnostics).

Changes

  • Bound ensureMeaningfulUpstream(resp, timeout) with a deadline that reuses QODER_STREAM_TTFB_MS / Direct.ttfb / resolveFirstByteTimeout() (default 30s).
  • On timeout: close the body and return emptyUpstreamError() (upstream_empty) so the executor can fail over.
  • On success: stop the timer and replay peeked bytes unchanged.
  • Apply the same bound to internal/providers/qwenwork ensureMeaningfulUpstream (30s default) for consistency — same hang shape.
  • Unit tests: heartbeat-only forever → times out with upstream_empty; meaningful line within bound → success + bytes preserved.
  • Changelog fragment + deploy README note that TTFB also covers the first meaningful SSE line.

Test plan

  • go test ./internal/providers/qoder/ ./internal/providers/qwenwork/
  • python3 scripts/release-notes.py self-test && validate
  • CI green on this PR
  • Local Docker rebuild + smoke (follow-up on Mac)

Do not merge from this PR description; leave for review.

Reuse QODER_STREAM_TTFB_MS / Direct.ttfb so heartbeat-only SSE after a
200 fails over with upstream_empty instead of hanging forever.
Apply the same deadline to qwenwork for consistency.
The TTFB timeout timer and the read-error path both Close the body;
cancelOnCloseBody.Close is not concurrency-safe, so race detector
failed TestDirectChatStreamTimesOutHeartbeatOnlyUpstream. Use sync.Once.
@caigee-cmd
caigee-cmd merged commit 626d58a into main Oct 22, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant