Skip to content

fix(proxy): time out an origin body that goes idle - #22

Merged
jamiehdev merged 2 commits into
mainfrom
fix/origin-body-idle-timeout
Sep 27, 2026
Merged

jamiehdev merged 2 commits into
mainfrom
fix/origin-body-idle-timeout

Conversation

@jamiehdev

@jamiehdev jamiehdev commented Sep 27, 2026 •

Copy link
Copy Markdown
Owner

An origin can send response headers and part of the body, then go silent. The proxy then no longer holds the client connection and the pooled origin connection open indefinitely. The proxy now applies --upstream-timeout-seconds to silence during the response body. When the origin sends no data for that period, the proxy logs a warning with the target URI. It then ends the client's response with an error. With a coalesced miss, the proxy releases the waiting requests at that point, and each goes to the origin itself.

Changes

  • A stream wrapper around the origin body resets its timer on each poll that follows a chunk. Time that actix spends on a slow client does not count against the origin.
  • The error closes the client connection before the body is complete. A Content-Length response ends short, and a chunked response gets no last chunk. The Tee drops its copy, so the cache stores nothing and the flight guard drops.
  • Background revalidation reads the body through the same wrapper. On a timeout it stores nothing and drops the refresh guard, so a later stale request can start another revalidation.
  • The current timeout option sets the idle period, so the proxy has no new flag. That option already defines how long the origin can stay silent before headers.

Verification

On main, these five tests fail because the proxy keeps the connection open past the 10 second test limit:

  • body_idle::sized_body_that_stalls_closes_the_client_connection_short
  • body_idle::chunked_body_that_stalls_gets_no_last_chunk
  • body_idle::stalled_cacheable_body_is_not_stored
  • coalescing::followers_of_a_leader_whose_body_stalls_are_released_when_it_is_given_up
  • body_idle::background_revalidation_whose_body_stalls_is_given_up, which checks that background_refreshes reaches 2

body_idle::slow_but_steady_body_arrives_whole passes on main. It fails after 1 second against a version of the wrapper that never resets its timer.

Not run: a check of the warning log line.

@jamiehdev
jamiehdev merged commit 1413a48 into main Sep 27, 2026
2 checks passed
@jamiehdev
jamiehdev deleted the fix/origin-body-idle-timeout branch September 27, 2026 17:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant