fix: resolve duplicate-file failures, alreadySafe reset, and backup restart loop
BackupEngine: after all retries fail, call fileExists() before recording a failure. If the file is on NAS (uploaded earlier but fileExists silently threw on the pre-check), count it as skipped and add it to manifestEntries — this ensures writeManifest includes every safe asset and prevents alreadySafe from dropping to 1 after the post-backup reconcile. BackupView: remove the immediate refreshAndWait from onChange(.failed). That call raced with refreshAfterBackup's writeManifest, cancelled the manifest- correct refresh, then reconciled against a stale 1-entry NAS manifest. Auto-resolve (.failed → .completed when needBackup == 0) is now owned by the coordinator so it runs after writeManifest finishes. AutoBackupCoordinator: add backupTriggerArmed flag (set by onActive/ handleNASReachable, cleared by handleReconciliationComplete). Post-backup reconciles from refreshAfterBackup are no longer able to re-trigger auto- backup — only an explicit app-open or LAN-join can arm the trigger. Also added auto-resolve: calls engine.resolveSuccess() when job is .failed but needBackup == 0, which fires the .completed green-flash path in BackupView. Co-Authored-By: Kutesir <kutesir@provoc.ug> Co-Authored-By: Sentry <sentry@provoc.ug>
This commit is contained in:
@@ -153,18 +153,11 @@ struct BackupView: View {
|
||||
try? await Task.sleep(nanoseconds: 500_000_000)
|
||||
statusService.refresh(force: true)
|
||||
}
|
||||
} else if case .failed = status {
|
||||
// Reconcile — if all files landed on NAS despite the failure, auto-resolve to .completed
|
||||
Task {
|
||||
await statusService.refreshAndWait(force: true)
|
||||
if statusService.snapshot.needBackup == 0 {
|
||||
engine.resolveSuccess()
|
||||
withAnimation(.spring(response: 0.3, dampingFraction: 0.8)) { ctaFlashGreen = true }
|
||||
try? await Task.sleep(nanoseconds: 2_500_000_000)
|
||||
withAnimation(.spring(response: 0.5, dampingFraction: 0.8)) { ctaFlashGreen = false }
|
||||
}
|
||||
}
|
||||
}
|
||||
// .failed auto-resolve is owned by AutoBackupCoordinator.handleReconciliationComplete.
|
||||
// It waits for refreshAfterBackup's writeManifest to finish before reconciling, then
|
||||
// calls engine.resolveSuccess() when needBackup == 0, which re-triggers .completed above.
|
||||
// Calling refreshAndWait here would race with writeManifest and read a stale NAS manifest.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user