Skip to content

fix(minimald): bound diag stream on reader idleness, not total transfer - #936

Closed
norrietaylor wants to merge 1 commit into
mainfrom
fix/915-diag-stream-idle-timeout
Closed

fix(minimald): bound diag stream on reader idleness, not total transfer#936
norrietaylor wants to merge 1 commit into
mainfrom
fix/915-diag-stream-idle-timeout

Conversation

@norrietaylor

@norrietaylor norrietaylor commented Jul 23, 2026

Copy link
Copy Markdown
Member

What

Replace the diag bundle pump's whole-transfer STREAM_TIMEOUT with an
idleness bound. serve_stream_diag_bundle previously wrapped
tokio::io::copy in a single 300s tokio::time::timeout, so the timeout
capped the entire transfer rather than reader inactivity.

build_bundle runs up to fifteen collectors back to back, each deadlined
individually at COLLECTOR_TIMEOUT (30s) — a worst case of 450s. On a
wedged host (the exact host a diagnostic bundle is wanted from), a bundle
the client is actively reading could outlast the fixed 300s total and be
cut off mid-stream, delivering a truncated archive. The expiry error also
blamed the client ("client stopped reading the bundle …") regardless of
whether the stall was server-side collection.

How

Add pump_until_idle, a manual read/write copy loop whose deadline resets
on every chunk that moves and fires only when a single read-or-write step
makes no progress for STREAM_TIMEOUT. A slow-but-progressing transfer now
runs as long as bytes keep flowing; a genuine stall — a client that stops
reading, or a build that emits nothing at all for the window — is still
bounded. The drop-order and cancellation invariants around rx/writer
that the original relied on are preserved. Reword the expiry error to name
the stall without asserting which side caused it.

Progress is measured on the compressed bytes reaching the channel; the doc
comments state this honestly rather than claiming total decoupling from the
collection budget.

Tests

Two unit tests cover the new semantics: a slow-but-progressing transfer
whose total duration exceeds the idle bound completes without a timeout,
and a stalled reader trips a TimedOut error whose message asserts no
blame. cargo test -p minimald passes (20 diag tests); cargo fmt --check
and cargo clippy -p minimald are clean for the touched file.

Closes #915

Note

Bound minimald diagnostic stream timeout on reader idleness rather than total transfer duration

  • Replaces tokio::time::timeout wrapping tokio::io::copy in stream_diag_bundle with a new pump_until_idle utility that resets the deadline on each chunk of progress.
  • Transfers that keep making progress can now run indefinitely; the timeout only fires after STREAM_TIMEOUT (300s) of inactivity on either side.
  • Timeout error messages now report lack of progress neutrally instead of blaming the client.
  • Two unit tests are added to diag.rs: one verifying slow-but-progressing transfers complete, one verifying stalled readers time out with ErrorKind::TimedOut.

Macroscope summarized 7c6f752.

The diag bundle pump wrapped `tokio::io::copy` in a single 300s
`STREAM_TIMEOUT`, capping the whole transfer. But `build_bundle` runs up
to fifteen 30s-deadlined collectors back to back, so on a wedged host — the
very host a diagnostic bundle is wanted from — a bundle the client is
actively reading can outlast the fixed total and be cut off mid-stream,
delivering a truncated archive. The expiry error also blamed the client
unconditionally, even when a slow server-side collection caused the stall.

Replace the whole-transfer bound with `pump_until_idle`, a manual copy loop
whose deadline resets on every chunk that moves and fires only when a single
read-or-write step makes no progress for `STREAM_TIMEOUT`. A slow-but-
progressing transfer now runs as long as bytes keep flowing; a genuine stall
(a client that stops reading, or a wedged builder) is still bounded. Reword
the expiry error to name the stall without asserting which side caused it.

Closes #915

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a87f0b82-868b-41e6-97ab-27eb60c3a04c

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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

@norrietaylor

Copy link
Copy Markdown
Member Author

Superseded by #927, which landed the same idle-based diag stream timeout on main (commit 7fd582e) while this was in flight. #927 bounds each write to the client on STREAM_IDLE_TIMEOUT (per-write, not whole-transfer) — the exact fix this PR targeted. Closing as duplicate; #915 is resolved by #927.

@norrietaylor
norrietaylor deleted the fix/915-diag-stream-idle-timeout branch July 23, 2026 21:52
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.

minimald: diag STREAM_TIMEOUT caps the whole bundle transfer, not reader idleness

1 participant