diff --git a/Outpost/Root/RootView.swift b/Outpost/Root/RootView.swift index 598475c..5fd90d4 100644 --- a/Outpost/Root/RootView.swift +++ b/Outpost/Root/RootView.swift @@ -50,12 +50,26 @@ struct RootView: View { // off — no need to wait for the user to open Settings and hit Retry. // Also catches Full Local Sync back up immediately, rather than // leaving it to wait out the rest of the periodic loop below. + // + // The flush itself gets a retry loop with a cooloff, not just one + // attempt: a single transient failure (one bad operation, a blip + // mid-flush) used to leave everything else stuck until the user + // manually hit Retry or connectivity changed again. Keeps retrying + // every 5 minutes for as long as *anything* is still pending and + // this signal stays on — stops on its own once the queue is empty, + // and `.task(id:)` cancels/restarts it automatically if + // isEffectivelyOnline flips again in the meantime. .task(id: isEffectivelyOnline) { guard isEffectivelyOnline, let cachingClient = session.cachingClient else { return } - _ = await cachingClient.flushPendingOperations() if isFullLocalSyncEnabled { _ = await cachingClient.performFullSync() } + while !Task.isCancelled { + _ = await cachingClient.flushPendingOperations() + let remaining = await cachingClient.pendingOperations() + guard !remaining.isEmpty else { break } + try? await Task.sleep(for: .seconds(300)) + } } // Fully automatic — this is the only place Full Local Sync actually // runs from (Settings' "Sync Now" is just an on-demand nudge at the