cli: avoid whole-file remote download timeouts - #1810
Conversation
object_store's 30s request timeout covers connect through the entire body, so mcap filter --allow-remote-scan of a large remote file dies after retries exhaust the 180s budget. Use a long per-GET timeout for downloads, stall detection, and ranged parts with a fresh retry budget. Co-authored-by: adrian <adrian@foxglove.dev>
| })? | ||
| } | ||
| }; | ||
| let written = self.stream_get_to_writer(response, writer, &mut progress)?; |
There was a problem hiding this comment.
The "resume on the next part instead of restarting the whole object" property only holds between parts. object_store's fresh retry budget covers each part's head request, but a stall (120s) or a mid-body connection drop inside stream_get_to_writer bubbles up here via ? and aborts the entire download — discarding every byte already written to the temp file. So on a flaky link, one TCP reset in any single 64MiB part restarts from zero, which is the exact failure mode this PR set out to kill.
You already track offset and pin the ETag — re-issuing offset..end on a body error/stall (bounded retries) is what makes this genuinely resumable. This is the same root cause as your question #2 (stall at 95%); worth handling body errors and stalls together rather than only stalls. What does the user see today if the connection blips 30GB into a 40GB download — a full restart? 😭
|
Tested this out in the environment in which I originally saw the issue, it appears to have fixed the issue |
Context
mcap filter --allow-remote-scanof a large remote file (the ~40GB S3 case in #1803 (comment)) fails after about 3 minutes with nestedoperation timed out/request or response body error. Indexed commands (info,list,get) are unaffected because they only fetch a small tail.object_store 0.13.2 applies a 30s client timeout from connect through the entire response body. Progress does not reset it. Failed attempts are retried until the 180s retry budget is exhausted, which matches the reporter's timing. v0.0.62 (Go CLI) did not have this timeout.
Local repro is transfer duration, not file size: a throttled HTTP body that takes longer than 30s hits the same error. Loopback 40GB can finish in under 30s, so throttling is the right repro, not a huge local file.
Approach
Whole-file downloads now:
parse_url_opts(so GCSallow_httpand other builder defaults stay intact).7days) on the download path only. Indexed/bounded reads still use the default 30s timeout. Connect timeout is unchanged.If-Match) so a mid-download overwrite fails instead of tearing the file.Rangeor the object is empty (HTTP 416).Downloading X / Y).No new
--timeoutflag.This does not make
filterindexed. Rewrite commands still materialize the whole remote file; that remains a follow-up.Testing
"416"substring).cargo clippy -p mcap-cli --all-targets -- --no-deps -D warningscargo test -p mcap-cliQuestions for review
These are product choices I made and would like input on:
If-Match. A replaced object fails withremote object changed while downloading.Related: Linear DB-1587. This PR addresses the filter timeout in #1803; it does not close that issue (credentials /
~/.awsare separate, see #1808).