Skip to content

Commit 264d2e1

Browse files
authored
fix: batch CloudKit push to respect 400-item limit (#342)
1 parent 2c1e9ff commit 264d2e1

1 file changed

Lines changed: 26 additions & 2 deletions

File tree

TablePro/Core/Sync/CloudKitSyncEngine.swift

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,35 @@ actor CloudKitSyncEngine {
5050

5151
// MARK: - Push
5252

53+
/// CloudKit allows at most 400 items (saves + deletions) per modify operation
54+
private static let maxBatchSize = 400
55+
5356
func push(records: [CKRecord], deletions: [CKRecord.ID]) async throws {
5457
guard !records.isEmpty || !deletions.isEmpty else { return }
5558

59+
// Split into batches that fit within CloudKit's 400-item limit
60+
var remainingSaves = records[...]
61+
var remainingDeletions = deletions[...]
62+
63+
while !remainingSaves.isEmpty || !remainingDeletions.isEmpty {
64+
let batchSaves: [CKRecord]
65+
let batchDeletions: [CKRecord.ID]
66+
67+
let savesCount = min(remainingSaves.count, Self.maxBatchSize)
68+
batchSaves = Array(remainingSaves.prefix(savesCount))
69+
remainingSaves = remainingSaves.dropFirst(savesCount)
70+
71+
let deletionsCount = min(remainingDeletions.count, Self.maxBatchSize - savesCount)
72+
batchDeletions = Array(remainingDeletions.prefix(deletionsCount))
73+
remainingDeletions = remainingDeletions.dropFirst(deletionsCount)
74+
75+
try await pushBatch(records: batchSaves, deletions: batchDeletions)
76+
}
77+
78+
Self.logger.info("Pushed \(records.count) records, \(deletions.count) deletions")
79+
}
80+
81+
private func pushBatch(records: [CKRecord], deletions: [CKRecord.ID]) async throws {
5682
try await withRetry {
5783
let operation = CKModifyRecordsOperation(
5884
recordsToSave: records,
@@ -83,8 +109,6 @@ actor CloudKitSyncEngine {
83109
self.database.add(operation)
84110
}
85111
}
86-
87-
Self.logger.info("Pushed \(records.count) records, \(deletions.count) deletions")
88112
}
89113

90114
// MARK: - Pull

0 commit comments

Comments
 (0)