commit 965ebcaa3d790b9fff69870b35a740767951dd11
parent 62c87f7137e99bdfd3346578de94b9ed7d4879ff
Author: Michael Camilleri <[email protected]>
Date: Mon, 27 Jul 2026 13:12:30 +0900
Remove redundant manual CloudKit subscriptions
Every launch performed extra CloudKit reads and writes to create private
and shared database subscriptions that CKSyncEngine neither used nor
retained. Diagnostics show remote notifications arriving through
CKSyncEngine's own subscriptions in both scopes. This commit removes the
parallel subscription setup and leaves its lifecycle to CKSyncEngine.
Co-Authored-By: Codex GPT 5.6 Sol <[email protected]>
Diffstat:
2 files changed, 1 insertion(+), 53 deletions(-)
diff --git a/Crossmate/Sync/SyncEngine.swift b/Crossmate/Sync/SyncEngine.swift
@@ -449,11 +449,6 @@ actor SyncEngine {
// MARK: - Lifecycle
- /// Database subscription IDs. Stable, per-scope, idempotent on re-creation
- /// so we can always attempt a save without first listing.
- private static let privateSubscriptionID = "crossmate-private-db-subscription"
- private static let sharedSubscriptionID = "crossmate-shared-db-subscription"
-
/// Creates both `CKSyncEngine` instances, restoring previously-saved state
/// so pending changes and change tokens survive restarts. Call once after
/// wiring callbacks. Idempotent — extra calls are no-ops so a race between
@@ -496,53 +491,6 @@ actor SyncEngine {
// so re-add every durable Ping on startup. Record IDs are stable and
// CKSyncEngine deduplicates repeated pending saves.
reconcilePendingPingOutbox()
-
- // CKSyncEngine's automatic subscription creation is unreliable in
- // practice — diagnostics on real devices showed both scopes with zero
- // subscriptions even after a healthy initial fetch and push, which
- // means CloudKit never fires pushes and the engine silently degrades
- // to its periodic poll. Create the database subscriptions ourselves;
- // CKDatabase.save is idempotent for an existing subscriptionID.
- Task { await ensureDatabaseSubscriptions() }
- }
-
- private func ensureDatabaseSubscriptions() async {
- await ensureDatabaseSubscription(
- database: container.privateCloudDatabase,
- subscriptionID: Self.privateSubscriptionID,
- label: "private"
- )
- await ensureDatabaseSubscription(
- database: container.sharedCloudDatabase,
- subscriptionID: Self.sharedSubscriptionID,
- label: "shared"
- )
- }
-
- private func ensureDatabaseSubscription(
- database: CKDatabase,
- subscriptionID: String,
- label: String
- ) async {
- do {
- let existing = try await database.allSubscriptions()
- if existing.contains(where: { $0.subscriptionID == subscriptionID }) {
- await trace("\(label) subscription already present (\(subscriptionID))")
- return
- }
- } catch {
- await trace("\(label) allSubscriptions probe failed: \(describe(error)) — attempting save anyway")
- }
- let subscription = CKDatabaseSubscription(subscriptionID: subscriptionID)
- let info = CKSubscription.NotificationInfo()
- info.shouldSendContentAvailable = true
- subscription.notificationInfo = info
- do {
- _ = try await database.save(subscription)
- await trace("\(label) subscription created (\(subscriptionID))")
- } catch {
- await trace("\(label) subscription save FAILED: \(describe(error))")
- }
}
/// Kicks CKSyncEngine's outbound drain after pending state has been queued.
diff --git a/Tests/Unit/LogScrubberTests.swift b/Tests/Unit/LogScrubberTests.swift
@@ -58,7 +58,7 @@ struct LogScrubberTests {
@Test("Prose, subscription IDs, and decimal timestamps pass through")
func passthrough() {
let messages = [
- "private subscription already present (crossmate-private-db-subscription)",
+ "remote notification: sub=CKSyncEngineDatabaseSubscription-Private",
"shared zone discovery: nothing new (server=23, known=23)",
"freshen game list foreground: private skipped (cooldown, last 7s ago)",
]