Skip to content

fix: Incremental sync failing to resume - WPB-28101 - #5179

Open
samwyndham wants to merge 11 commits into
developfrom
fix/sync-not-resuming-WPB-28101
Open

fix: Incremental sync failing to resume - WPB-28101#5179
samwyndham wants to merge 11 commits into
developfrom
fix/sync-not-resuming-WPB-28101

Conversation

@samwyndham

@samwyndham samwyndham commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator
BugWPB-28101 [iOS] [Sync] Persistent loading bar remains stuck after backgrounding app during active sync by user

Issue

This PR fixes an issue where an unfinished suspension of sync when going to the background interferes and prevents sync from resuming when returning to the foreground. This has been seen to happen when the device is backgrounded when performing a request to /access?client_id=<some client id> as part of an incremental sync that is still not complete / cancelled when resuming by returning to the foreground.

This PR attempts to fix this by making it so that if there is an ongoing suspend() when resume() is called, resume() is deferred to after the suspension is complete.

I don't expect this to fix all issues here. Larger changes are probably necessary. But I hope this improves the situation somewhat.

Testing

These steps require a proxy app. Setup is complex so first try the following steps with a known broken version to ensure you can reproduce the issue.

  1. Log in to a staging account (proxies don’t work with production accounts)
  2. Configure proxy app. Find calls to <https://staging-nginz-https.zinfra.io/access?client_id= client id>
  3. Configure proxy to breakpoint (e.g. pause) on requests to POST <https://staging-nginz-https.zinfra.io/access?client_id= client id>
  4. Restart the app
  5. Proxy should block the above request
  6. Wait around 10 seconds
  7. Background the app. Wait 10 seconds
  8. Foreground the app. Wait a couple of seconds.
  9. Execute the breakpoint(s) in 3 so that the requests complete.
  10. Sync should complete and sync bar should disappear.

Checklist

  • Title contains a reference JIRA issue number like [WPB-XXX].
  • Description is filled and free of optional paragraphs.
  • Adds/updates automated tests.

Copilot AI lite review requested due to automatic review settings September 2, 2026 13:59

Copilot AI 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.

🟡 Changes recommended

The new suspension/resume state introduces a likely data race (concurrent resume()/suspend() access to non-isolated properties) that can still lead to missed or duplicated resumes under real multi-task call patterns.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR addresses a sync lifecycle edge case in wire-ios-sync-engine where an in-progress suspension (e.g., app backgrounding mid-sync) can prevent a subsequent foreground resume from restarting incremental sync.

Changes:

  • Queue resume() requests that occur while suspend() is still running, and trigger the resume once suspension completes.
  • Add a unit test covering “resume during suspension” to prevent regressions.
File summaries
File Description
wire-ios-sync-engine/Source/Synchronization/SyncAgent.swift Adds “pending resume” state to defer resumes until an ongoing suspension finishes.
wire-ios-sync-engine/Tests/Source/Synchronization/SyncAgentTests.swift Adds a new async test that simulates a long-running suspension and verifies resume triggers only after completion.
Review details

Suppressed comments (1)

wire-ios-sync-engine/Source/Synchronization/SyncAgent.swift:212

  • pendingResume is consumed without being cleared, so (a) a subsequent call to suspend() could incorrectly see stale state until its initial reset runs, and (b) it’s easier to accidentally trigger duplicate resumes if additional logic later re-checks the flag. Clearing the pending request after capturing it makes the intent explicit and avoids reusing the same request.
        isSuspendingSync = false

        if let pendingResume {
            resume(callEventsOnly: pendingResume.callEventsOnly)
        }
  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread wire-ios-sync-engine/Source/Synchronization/SyncAgent.swift Outdated
@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Test Results

1 139 tests   1 139 ✅  1m 26s ⏱️
  132 suites      0 💤
    1 files        0 ❌

Results for commit 762d11e.

♻️ This comment has been updated with latest results.

Summary: workflow run #34336161079
Allure report (download zip): html-report-33253-fix_sync-not-resuming-WPB-28101

@datadog-wireapp

datadog-wireapp Bot commented Sep 2, 2026

Copy link
Copy Markdown

Tests

⚠️ Warnings

⚠️ Your PR has warnings. Please review the issues below.

❄️ 1 New flaky test detected

test_Resume_DuringSuspensionStartsNewSyncAfterSuspensionCompletes() from UnitTests.SyncAgentTests   View in Datadog
SyncAgentTests.swift:406: XCTAssertEqual failed: (&#34;1&#34;) is not equal to (&#34;2&#34;)

View in Flaky Test Management

ℹ️ Info

No other issues found (see more)

🧪 All tests passed

Useful? React with 👍 / 👎

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 762d11e | Docs | View more details | Give us feedback!

@samwyndham
samwyndham requested review from jullianm and netbe September 7, 2026 09:51

Copilot AI 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.

🟡 Changes recommended

The new unit test has a scheduling race that can make it flaky/non-deterministic without an explicit yield before asserting invocation counts.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 2
  • Review effort level: Lite

@netbe netbe 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.

left some suggestions.

question: Does the /access call come from WireNetwork or WireTransport ? I still would like to know why the call would fail resuming the sync: it might be an issue with cancellation of renewing the access token code

Comment thread wire-ios-sync-engine/Source/Synchronization/SyncAgent.swift Outdated
Comment thread wire-ios-sync-engine/Source/Synchronization/SyncAgent.swift
@samwyndham

samwyndham commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator Author

left some suggestions.

question: Does the /access call come from WireNetwork or WireTransport ? I still would like to know why the call would fail resuming the sync: it might be an issue with cancellation of renewing the access token code

@netbe The /access call is via WireNetwork. Looking at the refreshAccessToken code you are correct that cancelling refreshAccessToken() doesn't actually cancel the request. But I believe this is just one case of many that can lead to the issue this PR attempts to address as we have many places that don't handle cancellation well. I will create a new ticket shortly to address this issue.

The more general issue here is:

  1. The app moves to the background
  2. The app tries to suspend incremental sync
  3. Suspending is not finished by the time the app moves to the foreground - this could be because the app moved to the foreground again quickly or suspension took more than 30 seconds.
  4. The app resumes sync
  5. Suspending incremental sync from 2 completes (as cancelled) and suspends the new sink from 4.

To be clear this PR is definitely a patch to address the immediate issue.

@netbe netbe 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.

LGTM :)

@samwyndham

Copy link
Copy Markdown
Collaborator Author

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.

4 participants