Skip to content

fix(file-provider): Properly handle cancellations - #11001

Open
claucambra wants to merge 40 commits into
masterfrom
work/fp-cancellations
Open

claucambra wants to merge 40 commits into
masterfrom
work/fp-cancellations

Conversation

@claucambra

@claucambra claucambra commented Oct 5, 2026 •

Copy link
Copy Markdown
Collaborator

Resolves

Second fix for #10579

Summary

Ensures cancellation propagates through File Provider uploads, downloads, and thumbnail fetches. Previously, cancellation did not consistently reach the surrounding operation or its supporting network requests, allowing cancelled operations to continue, update database state, and potentially report success

Checklist

AI (if applicable)

@claucambra claucambra added this to the 35.0.0 milestone Oct 5, 2026
@claucambra claucambra self-assigned this Oct 5, 2026
@claucambra claucambra added os: 🍎 macOS Apple macOS, formerly also known as OS X feature: 📁 file provider macOS File Provider Extension, more general also known as virtual file system. labels Oct 5, 2026
@claucambra claucambra changed the title fix(file-provider): Properly handle fix(file-provider): Properly handle cancellations Oct 5, 2026
@i2h3

i2h3 commented Oct 6, 2026

Copy link
Copy Markdown
Collaborator

@claucambra Please rebase onto master and resolve the conflicts.

@claucambra
claucambra force-pushed the work/fp-cancellations branch from 67f30c7 to a27c618 Compare October 6, 2026 09:11
@claucambra

Copy link
Copy Markdown
Collaborator Author

@claucambra Please rebase onto master and resolve the conflicts.

Rebased and resolved now

@claucambra
claucambra force-pushed the work/fp-cancellations branch from a27c618 to 8336b0f Compare October 6, 2026 09:12

@i2h3 i2h3 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed at 8336b0f. Main points:

  1. A cancelled fetch is persisted as .downloadError, which blocks later depth-1 metadata updates for that item (Item+Fetch.swift).
  2. A chunked upload cancelled during assembly reports cancellation although the server committed the file (Upload.swift).
  3. Upload cancellation has no tests; the new upload mock hooks are unused.

The rest are edge cases and test-robustness notes. The NetworkOperationCancellation helper and the thumbnail batching look correct to me (Darwin invokes cancellationHandler asynchronously, so no lock re-entrancy; registrations are sequential).

Hygiene: only 2 of 22 commits carry an Assisted-by: trailer while the PR declares AI assistance; please add it where it applies. At ~2.4k changed lines across uploads, downloads, thumbnails, capabilities and account waits, splitting the helper + uploads from the download changes would ease review. The failing classic-client PermissionsTest is unrelated.

Review prepared with AI assistance (Claude Code) and checked against the head commit.

@claucambra claucambra modified the milestones: 35.0.0, 35.0.1 Oct 12, 2026
@claucambra
claucambra requested a review from i2h3 October 13, 2026 14:17
@claucambra
claucambra force-pushed the work/fp-cancellations branch from 0138514 to adce455 Compare October 15, 2026 06:03
Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
Signed-off-by: Claudio Cambra <developer@claudiocambra.com>

Assisted-by: Codex:GPT-6
Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
Signed-off-by: Claudio Cambra <developer@claudiocambra.com>

Assisted-by: Codex:GPT-6
Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
… acquisition

Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
…celled item fetch

Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
…der from overwriting what is newer state

Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
…ad contents

Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
…ail instead of hanging

Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
…d overlapping names

Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
…imeout, waiting for actual registration

Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
…ack to normal, downloaded set to false, no session error

Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
… for later changes

Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
…m NextcloudKit

Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
…chunked uploads through upload, create and modify

Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
…en more than one task depends on it

Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
…erly waiting for account setup

Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
…ownload

Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
Require the release that preserves committed chunk-upload results when
cancellation arrives during assembly.

Assisted-by: Codex:GPT-6

Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
Verify create and modify persist completed chunked uploads despite
cancellation, including the server identity, ETag and chunk cleanup.

Reopen Realm after the async modify before checking chunk rows so the
existing exclusion test does not access a Realm from another thread.

Assisted-by: Codex:GPT-6

Signed-off-by: Claudio Cambra <developer@claudiocambra.com>
@claucambra
claucambra force-pushed the work/fp-cancellations branch from adce455 to 5890733 Compare October 15, 2026 06:10
@sonarqubecloud

Copy link
Copy Markdown

@i2h3 i2h3 left a comment •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

  1. b4361ca clears deleted on unchanged rows in every non-paginated depth-1 read, which brings back local-only deletions (inline).
  2. cancelledWaiterDoesNotWaitForAccountTimeout still hangs instead of failing if cancellation regresses (inline).
  3. 4 of 40 commits mention Assisted-by: Codex:GPT-6, and in each a blank line separates it from Signed-off-by, so git parses only one of the two as a trailer. Please add the trailer to every commit with AI-assisted content, in the same block as Signed-off-by.

Review prepared with AI assistance (Claude Code) and checked against the head commit.

if existingMetadata.status == Status.normal.rawValue, !existingMetadata.isInSameDatabaseStoreableRemoteState(updatedMetadata) {
// Clear a stale deleted flag even when the server returns unchanged metadata.
if existingMetadata.status == Status.normal.rawValue,
existingMetadata.deleted || !existingMetadata.isInSameDatabaseStoreableRemoteState(updatedMetadata)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This clears deleted on every unchanged .normal row in each non-paginated depth-1 read (working-set scan, change enumeration, directory fetch). Some tombstones are local-only on purpose while the server copy stays unchanged: deleting an ignored file (Item+Delete.swift:64-69) and consuming the excluded-from-sync marker of a bundle (Item+Delete.swift:49-61). The next read of their parent now reports them again through didUpdate, so a deleted ignored file comes back and an excluded bundle's server copy is re-reported at the path of the user's local copy. The paginated path already did this through addItemMetadataPreservingLocalState, but this change extends it to the frequent paths, and the cancellation fix does not need it. If the package case from my earlier comment needs a live child row, could fetchDirectoryContents upsert the listed child before beginDownload, as base did with addItemMetadata? A general tombstone change would fit its own PR, with tests that an ignored file and an excluded bundle stay deleted after their parent is read.

var iterator = waiting.makeAsyncIterator()
_ = await iterator.next()
task.cancel()
await #expect(throws: CancellationError.self) { try await task.value }

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

If onCancel in awaitAccount stops resuming the waiter, which is what this test guards, task.value never returns: the timeout is UInt64.max, nothing calls signalAccountReady(), and awaiting an unstructured task's value does not react to .timeLimit cancelling the test. The Tests job has no timeout-minutes, so CI would hang rather than fail. Wrapping it as Task<Bool, Never> (true when CancellationError was thrown) so testTaskValue(of:) can bound it, plus defer { ext.signalAccountReady() } as in the next test, would make it fail instead.

@claucambra claucambra modified the milestones: 35.0.1, 35.0.2 Oct 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature: 📁 file provider macOS File Provider Extension, more general also known as virtual file system. os: 🍎 macOS Apple macOS, formerly also known as OS X

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants