Skip to content

feat: cancel downloads per caller without breaking FileService - #548

Open
ben-milanko wants to merge 1 commit into
Baseflow:mainfrom
Railway-Engineering-Solutions:feat/request-cancellation
Open

ben-milanko wants to merge 1 commit into
Baseflow:mainfrom
Railway-Engineering-Solutions:feat/request-cancellation

Conversation

@ben-milanko

Copy link
Copy Markdown

✨ What kind of change does this PR introduce? (Bug fix, feature, docs update...)

Feature: per-caller request cancellation. This is the second of the two pull requests suggested in the review of #504. Web persistence is in a separate PR.

⤵️ What is the current behavior?

A download cannot be cancelled once requested. A widget that is disposed, or scrolled away, still waits for its download to finish.

🆕 What is the new behavior (if this is a feature change)?

  • getFileStream, getSingleFile, downloadFile and ImageCacheManager.getImageFile take an optional CancellationToken. Cancelling ends that call with a CancelledException.
  • Cancellation applies per caller. Callers of the same url share one download, and each gets its own stream. The download, and a shared resize, stops only once every caller has cancelled. A caller without a token keeps the download running, and one caller's token never fails or is ignored for another caller.
  • A cancelled or failed download deletes its partial file. Downloads go to a fresh path, so the previously cached file stays valid.
  • The download sink is closed when the response stream errors, as the old .pipe(sink) did.

💥 Does this PR introduce a breaking change?

No. FileService.get and BaseCacheManager keep their exact signatures. The token reaches the file service as CancellationToken.current, a zone value. HttpFileService aborts its request on it, and a custom FileService that ignores it is simply abandoned and its late response body released. flutter_cache_manager_firebase analyzes and passes its tests unchanged against this branch, without a dependency override.

🐛 Recommendations for testing

  • flutter test: 168 tests pass, including a new test/cancellation_test.dart. It covers mid-stream cancellation, a response stream error, two callers on one url (in both orders), every caller cancelling, a queued request, an already-cancelled token, a service that ignores the token, and the token passing through getFileStream, getSingleFile, downloadFile and getImageFile, with and without resizing.
  • test/mock.mocks.dart is regenerated for the new optional parameter on WebHelper.downloadFile.
  • flutter build web --wasm in example/ builds.

📝 Links to relevant issues/docs

Follows the review of #504.

🤔 Checklist before submitting

  • All projects build
  • Follows style guide lines (code style guide)
  • Relevant documentation was updated
  • Rebased onto current main
  • Version bumped and dated CHANGELOG entry added

Both this PR and the web persistence PR bump to 3.6.0. Whichever merges second will move to the next minor version when rebased.

Adds an optional CancellationToken to getFileStream, getSingleFile,
downloadFile and ImageCacheManager.getImageFile.

- FileService.get and BaseCacheManager keep their signatures. The token
  reaches the file service as CancellationToken.current, a zone value
  set with runScoped; HttpFileService aborts its request on it, and a
  service that ignores it is abandoned with its late body released.
  flutter_cache_manager_firebase compiles and passes unchanged.
- Callers of the same url share one download through SharedCancellation,
  which gives each its own stream; the download (and a shared resize)
  stops only once every caller has cancelled, and a caller without a
  token keeps it alive.
- A cancelled or failed download deletes its partial file. Downloads go
  to a fresh path, so the previously cached file stays valid.
- The sink is closed when the response stream errors.
- Tests cover mid-stream cancellation, a stream error, two callers on
  one url in both orders, every caller cancelling, a queued request, an
  already-cancelled token, a service that ignores the token, and the
  token through getFileStream, getSingleFile, downloadFile and
  getImageFile with and without resizing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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