Skip to content

fix(remote-transfer): keep file transfers running instead of timing out - #3235

Open
bobleer wants to merge 1 commit into
GCWing:mainfrom
bobleer:bob/fix-remote-transfer-request-timeout
Open

bobleer wants to merge 1 commit into
GCWing:mainfrom
bobleer:bob/fix-remote-transfer-request-timeout

Conversation

@bobleer

@bobleer bobleer commented Sep 27, 2026

Copy link
Copy Markdown
Collaborator

Summary

Remote workspace transfers no longer inherit one 30s frontend request deadline, and both providers (SFTP and container) now stream, stage, and publish the same way.

Root cause of the reported failure: the shared ApiClient applied its default 30s deadline to every Tauri command, including remote_download_to_local_path / remote_upload_from_local_path. A slow-but-healthy transfer was aborted client-side with Request timeout while the host kept transferring, and the progress listener was torn down at the same moment, so the UI reported a failure for a transfer that could still complete. The same single deadline also hid whole-file buffering on both sides, an inconsistent cancel path, and a stop action that never reached drag-and-drop uploads.

No upstream issue: this was reported directly against 1.0.2 behaviour ("文件传输失败:Error: Request timeout" while receiving files from a remote workspace).

Type and Areas

Type: bug fix / robustness fix.

Areas: desktop/Tauri, web UI, Rust core (remote SSH services), docs.

Motivation / Impact

For users:

  • a transfer runs to completion instead of failing at 30s, and the stop button on the transfer card actually cancels the operation it displays (before this, a drag-and-drop upload could not be cancelled at all and a peer download could not be stopped);
  • a cancelled or failed upload/download leaves the previous destination unchanged instead of truncating or half-writing it;
  • large files no longer have to fit in memory on the client or the host.

For developers:

  • ApiRequestConfig.timeout <= 0 now means "no deadline" (previously 0 silently fell back to the default), so a long-running command can opt out explicitly; the two transfer commands use it, commands without a stop surface keep the default;
  • the SFTP per-request timeout went from the dependency default 10s to 60s, because 10s for one 256 KiB chunk is a ~25 KiB/s throughput floor that turned a slow-but-healthy link into a failing one;
  • the cancellation registry is now an RAII guard, so it cannot leak an entry on an early return.

Verification

  • cargo test -p openbitfun-services-integrations --no-default-features --features remote-ssh-concrete --lib remote_ssh:: — passed (163 passed, 5 ignored)
  • cargo test -p openbitfun-desktop --lib api::ssh_api::tests — passed
  • cargo test -p openbitfun-desktop --lib api::local_file_download::tests — passed
  • cargo test -p openbitfun-desktop --lib remote_workspace_policy — passed
  • cargo check -p openbitfun-services-integrations --no-default-features --features remote-ssh-concrete and --features remote-ssh — passed
  • cargo check -p openbitfun-desktop --lib — passed (needs the same Linux GTK/webkit build packages CI installs)
  • pnpm run type-check:web — passed
  • pnpm --dir src/web-ui run test:run src/tools/file-system src/features/ssh-remote src/infrastructure/api — passed (50 files / 440 tests)
  • pnpm run fmt:rs, pnpm run i18n:audit, pnpm run check:core-boundaries, pnpm run check:repo-hygiene, eslint on the changed files — passed
  • git diff --cached --check — clean

AI assistance: this change is AI-assisted. Automated testing level is fully tested according to the list above (unit/integration plus the repository's static checks); it was not manually exercised against a real remote host in this environment (no live SSH/container target was available), so an end-to-end transfer check on a real workspace is still worth doing during review.

Reviewer Notes

  • Remote scenarios: everything here is local to the desktop host and its Web UI. No wire shape, Tauri command name, event payload field, Product Operation Registry row, workspace_file_upload chunk protocol, or relay-service/mobile-web code changed — so no relay or mobile-web redeploy is involved, and no cross-version negotiation changes.
  • Behaviour change worth confirming: an upload now replaces its destination (new inode; the mode comes from the staging file) instead of truncating in place. That is the publish semantics the container path and the chunked workspace_file_upload already used, and it is what makes a cancelled upload non-destructive. Documented in docs/architecture/remote-workspace-transport.md.
  • Known gaps deliberately not bundled in this PR: peer-proxied transfers are still capped at 120s by the peer RPC policy and the peer host-invoke bridge, and commands without a progress/stop surface keep the default deadline on purpose (that bound is what ends a wedged host). Both are called out here rather than silently half-fixed.
  • New tests: streamed SFTP upload (progress, cancel, channel reuse), streamed container upload through the local shell fixture, desktop staging/registration units, ApiClient deadline opt-out, sshApi deadline boundary, drag-and-drop multi-file stop, peer-download stop.

Checklist

  • This PR is focused and does not include secrets, temporary prompts, generated scratch files, or unrelated artifacts.
  • Relevant verification is recorded above, or skipped checks are explained.
  • User-facing strings, docs, and locales are updated where applicable.

Generated with OpenBitFun

Every remote file command inherited one 30s frontend request deadline, so a
slow-but-healthy transfer was reported as "Request timeout" while the host kept
transferring. Transfers now stream instead of buffering whole files, stage the
destination and publish it only after the bytes completed, and carry one
cancellable transfer id from the progress card to the backend so a stop reaches
the operation it displays.

Co-authored-by: OpenBitFun <318544290+bitfun-ai@users.noreply.github.com>
@bobleer
bobleer requested a review from GCWing September 27, 2026 13:30
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