Skip to content

Retry transient Proton block failures without restarting the whole file #42

Description

@ClaudiuSchuster

Problem

A transient Proton Storage 502 currently aborts the complete file-upload
attempt even though the bridge still holds the encrypted blocks from the
current batch in memory. rclone's VFS then retries the file from the beginning.
For a large file this can retransmit tens of gigabytes and turn an otherwise
bounded upload into a many-hour operation.

PDrive's generation-bound recovery guard correctly avoids a service restart
while payload bytes continue to move. That guard cannot preserve work already
discarded inside one rclone file attempt, so this needs to be fixed in the
Proton API bridge upload path.

Sanitized live evidence

The issue was reproduced with PDrive's checksum-pinned rclone beta containing
the fresh-stream retry fix and the block-worker drain fix:

  • one 30.4 GiB VFS upload with a 4.8 MiB/s payload limit;
  • the same rclone process remained active for more than seven hours;
  • aggregate transfer accounting exceeded 65 GB while the current file attempt
    was still at roughly 16 GB / 49%;
  • six separated same-process 502 POST .../storage/blocks cycles were
    observed;
  • no systemd service restart occurred after the worker-drain build became
    active;
  • after the latest 502, the same PID resumed sustained payload progress.

This shows that the service-level recovery guard is behaving conservatively,
but whole-file VFS retries still discard substantial completed work.

Root cause

uploadAndCollectBlockData encrypts blocks in batches of eight 4 MiB blocks.
uploadPendingBlocks requests signed upload links, starts the block workers and
drains every result. If any worker returns an error, the function returns that
error immediately after draining the batch. The error propagates through
UploadFileByReader, and the caller can only retry the complete file stream.

The underlying API client retries rate limiting, 503, dial failures and
dropped connections, but it does not retry the observed 502. rclone's
low-level retry setting does not wrap this CallNoRetry upload path.

Expected behavior

  • Retry only transiently failed encrypted blocks from the current batch.
  • Request fresh signed upload links for the failed block indexes and create a
    fresh reader for every block attempt.
  • Retain successful blocks instead of replaying the complete batch or file.
  • Use a small bounded attempt count with context-aware backoff.
  • Drain every started worker before deciding whether to retry or return.
  • Return non-retryable errors immediately after the batch is drained.
  • Return the final concrete error when the bounded retry budget is exhausted.
  • Keep retry logs free of signed URLs, tokens, link IDs and file paths.

Safety boundaries

  • Stay inside the existing draft, revision and block indexes.
  • Do not delete cache data, drafts, revisions or remote files.
  • Do not retry authentication, draft-conflict or other client-side 4xx
    failures as storage transients.
  • Never loop indefinitely and always honor context cancellation.
  • Preserve the existing global upload-worker semaphore and worker-drain
    guarantee.

Acceptance criteria

  • A mixed batch retries only the failed transient blocks.
  • A later successful retry completes without rereading the file stream.
  • A non-retryable block failure is returned without another attempt.
  • Exhausted transient retries return the last useful error.
  • Cancellation during backoff returns promptly.
  • Concurrent failures do not leak upload-worker semaphore slots.
  • go test ./..., go test -race ./... and the repository linter pass.
  • PDrive continues to treat measurable payload progress as non-actionable and
    does not restart a healthy moving upload.

The bridge repositories currently have their GitHub issue trackers disabled,
so this cross-repository dependency issue is tracked here and implemented in a
focused bridge pull request.

Implementation status

Activity

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

Metadata

Metadata

Labels

bugSomething isn't workingenhancementNew feature or request

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions