imessage initial-sync robustness: hold watermark on partial failure + log progress every 50 convs

This commit is contained in:
quinn 2026-05-15 23:07:15 -07:00
parent e3078ab5fd
commit 19e4dc440a

View file

@ -239,8 +239,9 @@ final class SyncManager: BaseSyncManager<SyncStats, SyncError> {
log.info("Batch sent: \(sent) messages (running total: \(totalSynced))")
} catch {
totalFailed += window.count
log.warning("Batch failed (\(window.count) convs): \(error.localizedDescription)")
activityLog.warning("Batch failed, continuing...")
let detail = (error as NSError).userInfo.description
log.warning("Batch failed (\(window.count) convs, \(batchMsgs) msgs): \(error.localizedDescription) | \(detail)")
activityLog.warning("Batch failed (\(window.count) convs): \(error.localizedDescription)")
}
window.removeAll()
windowMessages = 0
@ -249,6 +250,10 @@ final class SyncManager: BaseSyncManager<SyncStats, SyncError> {
for conversation in conversations {
convIndex += 1
if convIndex % 50 == 0 {
log.info("initial-sync progress: \(convIndex)/\(conversations.count) iterated, synced=\(totalSynced) failed=\(totalFailed)")
activityLog.info("Progress: \(convIndex)/\(conversations.count) (synced \(totalSynced) msgs)")
}
do {
let messages = try imessageReader.getMessages(conversationId: conversation.id, since: nil)
if messages.isEmpty { continue }
@ -330,11 +335,23 @@ final class SyncManager: BaseSyncManager<SyncStats, SyncError> {
log.info("Initial sync complete - \(totalSynced) messages synced, \(totalFailed) conversations failed")
if let newDate = latestMessageDate {
// Only advance the watermark when every batch was accepted. A partial
// initial sync that advances the watermark would mask the missing
// conversations forever the regular incremental path filters by
// `date > lastSync` and would never retry them. Leaving the watermark
// unset means the next cycle re-enters performInitialSync (gated on
// server-side message count == 0) only after the operator truncates;
// for partial-failure mid-run we want the user to clear and retry,
// or for the loop to retry on the next syncNow.
if totalFailed == 0, let newDate = latestMessageDate {
setLastSync(newDate)
activityLog.success("Initial sync complete: \(totalSynced) messages synced")
} else if totalFailed > 0 {
log.warning("Initial sync partial — watermark NOT advanced (\(totalFailed) convs failed). Re-run will retry.")
activityLog.warning("Initial sync partial: \(totalSynced) synced, \(totalFailed) failed — will retry")
} else {
activityLog.success("Initial sync complete: \(totalSynced) messages synced")
}
activityLog.success("Initial sync complete: \(totalSynced) messages synced")
await fetchStats()
} catch {