commit 6fb82447f6f854d642d3d4d409e40f2fdd125f99
parent 6890a9ffc46dea73d83a204454285b81d144d8a6
Author: Michael Camilleri <[email protected]>
Date: Fri, 29 May 2026 16:19:47 +0900
Coalesce overlapping game-list refreshes
Diffstat:
1 file changed, 25 insertions(+), 0 deletions(-)
diff --git a/Crossmate/Services/AppServices.swift b/Crossmate/Services/AppServices.swift
@@ -121,6 +121,7 @@ final class AppServices {
private var sharedPushCatchUpTask: Task<Void, Never>?
private var isHandlingPrivateRemoteNotification = false
private var isHandlingSharedRemoteNotification = false
+ private var gameListFreshenTask: Task<Void, Never>?
private var isFresheningPrivateGameList = false
private var isFresheningSharedGameList = false
private var claimedPingRecordNames: Set<String> = []
@@ -1167,6 +1168,23 @@ final class AppServices {
func freshenGameList(reason: FreshenReason) async {
guard await ensureICloudSyncStarted() else { return }
+ if let task = gameListFreshenTask {
+ syncMonitor.note(
+ "freshen game list \(reason.diagnosticLabel): coalesced into in-flight freshen"
+ )
+ await task.value
+ return
+ }
+
+ let task = Task { @MainActor in
+ await self.runFreshenGameList(reason: reason)
+ }
+ gameListFreshenTask = task
+ await task.value
+ gameListFreshenTask = nil
+ }
+
+ private func runFreshenGameList(reason: FreshenReason) async {
// The game list is a foreground-visible freshness path, not the live
// collaboration path. Keep the two database scopes serialized so list
// appearance and foreground transitions do not create a read burst.
@@ -1199,6 +1217,13 @@ final class AppServices {
return
}
guard await ensureICloudSyncStarted() else { return }
+ if let task = gameListFreshenTask {
+ syncMonitor.note(
+ "freshen game list \(reason.diagnosticLabel): \(label) coalesced into in-flight freshen"
+ )
+ await task.value
+ return
+ }
await freshenGameListScope(scope, label: label, reason: reason)
await refreshSnapshot()
}