Skip to content

Prevent duplicate Storage requests on resume - #16771

Open
dajiaohuang wants to merge 4 commits into
firebase:mainfrom
dajiaohuang:fix/storage-task-enqueue-idempotency
Open

dajiaohuang wants to merge 4 commits into
firebase:mainfrom
dajiaohuang:fix/storage-task-enqueue-idempotency

Conversation

@dajiaohuang

@dajiaohuang dajiaohuang commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Prevent duplicate upload/download setup from immediate resume or pause/resume by rejecting obsolete enqueue generations before preparation and fetcher installation.
  • Cover public putData/getData followed by immediate resume without pause, and download resume from its progress callback while completion is held.
  • Correct the upload object-path fixture, bound XCTest waits, release test gates on teardown, and synchronize discard observation at all setup stages.
  • Update Unreleased changelog with Prevent duplicate Storage requests on resume #16771.

Validation

  • Four changed Swift files pass pinned SwiftFormat 0.55.5 lint and git diff --check.
  • Actual FirebaseStorageUnit/StorageTaskEnqueueTests on Xcode 26.4.1 and an iOS simulator: all five tests passed, zero failures, at source 3b0555b. This includes immediate upload/download resume, discarded earlier setup, and resume during download progress.
  • Native XCTest run uses the repository Swift Package test setup and real GTMSessionFetcher callbacks. The progress case controls internal progress state to avoid a transient-state timing dependency. This is focused class coverage; the full platform matrix remains separate.

@gemini-code-assist

Copy link
Copy Markdown
Contributor
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

@paulb777

paulb777 commented Oct 1, 2026

Copy link
Copy Markdown
Member

Thanks for the contribution! A few housekeeping items:

  • CHANGELOG: The entry in FirebaseStorage/CHANGELOG.md is under # 12.19.0, which has already shipped. Please move it under a # Unreleased heading at the top of the file (add the heading if it isn't there yet).
  • PR number: end the entry with this PR's number, e.g. - [fixed] Description. (#16771).
  • Formatting: after updating, please run scripts/style.sh so the infra.check job passes. It needs clang-format 23 and swiftformat (see scripts/setup_check.sh). If you can't run it locally, the infra.check log lists the files that need formatting.

@paulb777 paulb777 added this to the 13.1.0 - M188 milestone Oct 1, 2026
@paulb777

paulb777 commented Oct 1, 2026

Copy link
Copy Markdown
Member

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request prevents duplicate upload and download requests when resuming a task before its initial setup completes by introducing generation tracking (enqueueGeneration) in StorageDownloadTask and StorageUploadTask. Unit tests have been added to verify that earlier setups are discarded upon resumption. The review feedback highlights a potential data race in both task implementations where setupDiscardedHandlerForTesting is accessed outside of the lock, and suggests synchronizing this access by retrieving the handler under the lock before executing it.

Comment thread FirebaseStorage/Sources/StorageDownloadTask.swift
Comment thread FirebaseStorage/Sources/StorageUploadTask.swift
@paulb777 paulb777 self-assigned this Oct 1, 2026

@paulb777 paulb777 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this is easy to hit: putData(...) already enqueues, so an immediate resume() (or a quick pause()/resume()) runs setup twice and starts two fetchers, orphaning the first. The generation approach looks sound to me.

CI confirms one blocker: testUploadResumeDiscardsEarlierSetup crashes with Fatal error: Internal error enqueueing a Storage task in the SPM unit tests (e.g. spm (xcode-27, catalyst)). The cause is inline.

Coverage: please add tests for the most likely real-world trigger (putData(...).resume() and getData(...).resume() right after creation, with no pause()), and for download resume() during .progress.

Comment thread FirebaseStorage/Tests/Unit/StorageTaskEnqueueTests.swift Outdated
Comment thread FirebaseStorage/Tests/Unit/StorageTaskEnqueueTests.swift Outdated
Comment thread FirebaseStorage/Sources/StorageTask.swift Outdated
@dajiaohuang

Copy link
Copy Markdown
Contributor Author

Fixed the upload fixture to use child("object"), avoiding the nil metadata path. Both initial-setup and discard waits now use XCTest expectations with 10-second async fulfillment; teardown releases the service gate even after a timeout. Added immediate putData(...).resume() and getData(...).resume() variants without pause, plus a real download fetcher/progress-callback test that holds completion while exercising resume in a deterministic progress state and checks that only one request starts.

The discard handler now has stateLock-protected storage; notification copies the handler under the lock and invokes it outside the lock. Both task types notify at all three setup-discard stages (before preparation, after service acquisition, and before fetcher installation). Moved the changelog under Unreleased/#16771. Four-file pinned SwiftFormat 0.55.5 lint and git diff --check pass. The new Apple/GTMSessionFetcher XCTest coverage has not run on this Windows host; current-head native CI remains required.

@paulb777

paulb777 commented Oct 2, 2026

Copy link
Copy Markdown
Member

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request prevents duplicate upload and download requests when resuming a task before its initial request setup has completed. It introduces an enqueueGeneration counter in both StorageDownloadTask and StorageUploadTask to track and discard obsolete setup tasks, and adds corresponding unit tests to verify this behavior. No review comments were provided, so there is no additional feedback.

@dajiaohuang

Copy link
Copy Markdown
Contributor Author

The revised tests now run in the repository's actual Swift Package test target. At source 3b0555b, all five StorageTaskEnqueueTests passed with zero failures, including immediate upload/download resume and resume from the download progress callback: native XCTest results. These exercise the real GTMSessionFetcher callbacks with bounded waits and teardown gate release.

This branch has not been deployed

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants