Skip to content

[WRONG BRANCH] Bound stalled upstream response bodies - #176

Draft
luvs01 wants to merge 1 commit into
mainfrom
codex/propose-fix-for-header-only-timeout-issue
Draft

[WRONG BRANCH] Bound stalled upstream response bodies#176
luvs01 wants to merge 1 commit into
mainfrom
codex/propose-fix-for-header-only-timeout-issue

Conversation

@luvs01

@luvs01 luvs01 commented Aug 8, 2026

Copy link
Copy Markdown
Owner

Motivation

  • The header-only timeout helper previously cleared its timer when headers arrived, leaving response bodies (passthrough and non-streaming parse paths) without a body/idle timeout and allowing a headers-only or slow upstream to pin the proxy.

Description

  • Add a resettable response-body inactivity guard in src/lib/response-body-inactivity.ts that arms only while an upstream read is pending, resets on non-empty chunks, and aborts the upstream controller on inactivity without counting downstream backpressure as a stall.
  • Apply the guard to passthrough response bodies after headers and to adapter response bodies used for non-streaming parsing in src/server/responses/core.ts, using the configured stallTimeoutSec (ms = stallTimeoutSec * 1000, default 300_000ms).
  • Export the helper via src/server/index.ts so server consumers can reference it and preserve existing relay behavior for normal completion and client cancellation.
  • Add focused regression tests in tests/response-body-inactivity.test.ts that cover headers-only upstream stalls, byte progress resetting the deadline, downstream backpressure, and presence of both server call sites.

Testing

  • Ran bun test tests/response-body-inactivity.test.ts and the new tests passed.
  • Ran bun run typecheck (bun x tsc --noEmit) and it passed.
  • Ran bun run privacy:scan and it passed.
  • Attempted a full bun run test; the broader suite run encountered unrelated existing failures/timeouts (an auth-matrix assertion and a Grok model-list timeout) that are not caused by this change and prevented a complete end-to-end green run during this iteration.

Codex Task

Summary by CodeRabbit

  • New Features
    • Added response-body inactivity protection for upstream responses.
    • Requests now abort when response data stops arriving beyond the configured timeout.
    • Receiving data resets the inactivity timer, while normal completion and cancellation are handled safely.
    • A default 300-second timeout is applied when no custom stall timeout is configured.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown

⚠️ Wrong target branch

This pull request currently targets main, but pull requests must target one of dev.

@luvs01 Please retarget this PR to dev. All contributions go to dev; main receives only release promotions. See our Contributing guide for details. Thanks! 🙏

Its title has been prefixed with [WRONG BRANCH].

This pull request is being kept as a draft automatically. Once every issue above is resolved, it will be marked ready for review again.

@github-actions github-actions Bot changed the title Bound stalled upstream response bodies [WRONG BRANCH] Bound stalled upstream response bodies Aug 8, 2026
@github-actions
github-actions Bot marked this pull request as draft August 8, 2026 14:58
@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR adds guardResponseBodyInactivity and applies it to passthrough and adapter-based upstream responses. The guard resets on non-empty chunks, aborts stalled upstream requests, propagates errors, and handles downstream cancellation.

Changes

Response body inactivity protection

Layer / File(s) Summary
Guarded response stream
src/lib/response-body-inactivity.ts, src/server/index.ts
Adds and exports guardResponseBodyInactivity. The wrapper manages inactivity deadlines, forwards chunks, aborts stalled upstream operations, propagates errors, handles cancellation, and preserves response metadata.
Server integration and validation
src/server/responses/core.ts, tests/response-body-inactivity.test.ts
Applies the guard to passthrough and adapter-based responses. Passthrough responses use config.stallTimeoutSec or a 300-second default. Tests cover timeout abortion, timer reset, integration, and delayed downstream reads.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Upstream
  participant ResponseGuard
  participant Downstream
  participant AbortController

  Upstream->>ResponseGuard: Provide response body
  Downstream->>ResponseGuard: Read wrapped body
  ResponseGuard->>Downstream: Forward non-empty chunks
  ResponseGuard->>ResponseGuard: Reset inactivity deadline
  ResponseGuard->>AbortController: Abort upstream after inactivity timeout
  Downstream->>ResponseGuard: Cancel stream
  ResponseGuard->>AbortController: Abort upstream operations
Loading

Suggested labels: bug

Suggested reviewers: ingwannu

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change by identifying stalled upstream response bodies, although the branch marker adds minor noise.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/propose-fix-for-header-only-timeout-issue

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/server/responses/core.ts`:
- Line 2965: Update fetchTerminalGuardContinuation to pass the continuation
adapter response through guardResponseBodyInactivity before checking its status
or parsing the body, matching the initial upstreamResponse handling. Add a
regression test covering a headers-only continuation that stalls, and flag any
provider/adapter contract drift revealed by the fix.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 9d6fa39a-2d14-4f0c-ab68-439b689869ce

📥 Commits

Reviewing files that changed from the base of the PR and between 8a9c0ef and 792cc4b.

📒 Files selected for processing (4)
  • src/lib/response-body-inactivity.ts
  • src/server/index.ts
  • src/server/responses/core.ts
  • tests/response-body-inactivity.test.ts

}
break;
}
upstreamResponse = guardResponseBodyInactivity(upstreamResponse, upstream, stallTimeoutMs);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Guard terminal-continuation response bodies.

Line 2965 guards only the initial adapter response. fetchTerminalGuardContinuation fetches another adapter response at line 3090. It parses that body at lines 3231-3235 without an inactivity guard.

If the continuation sends headers and then stalls, the parser remains pending and the upstream turn remains active. Wrap the continuation response before checking its status or parsing its body. Add a regression test for a headers-only continuation response.

Proposed fix
-        response = await fetchContinuation(recoveryKind);
+        response = guardResponseBodyInactivity(
+          await fetchContinuation(recoveryKind),
+          upstream,
+          stallTimeoutMs,
+        );

As per path instructions, flag provider/adapter contract drift.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/server/responses/core.ts` at line 2965, Update
fetchTerminalGuardContinuation to pass the continuation adapter response through
guardResponseBodyInactivity before checking its status or parsing the body,
matching the initial upstreamResponse handling. Add a regression test covering a
headers-only continuation that stalls, and flag any provider/adapter contract
drift revealed by the fix.

Source: Path instructions

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant