Major update for stability
This commit is contained in:
@@ -23,6 +23,7 @@ final class BackgroundSyncManager: ObservableObject {
|
||||
@Published private(set) var isSyncAllRunning = false
|
||||
@Published private(set) var syncAllCompleted = 0
|
||||
@Published private(set) var syncAllTotal = 0
|
||||
@Published private(set) var lastError: String?
|
||||
|
||||
var activityDisplayTitle: String {
|
||||
if isSyncAllRunning {
|
||||
@@ -67,6 +68,7 @@ final class BackgroundSyncManager: ObservableObject {
|
||||
guard !started else { return }
|
||||
started = true
|
||||
refreshConfiguration()
|
||||
pruneHistoryIfNeeded(force: true)
|
||||
checkSchedules()
|
||||
timer = Timer.scheduledTimer(withTimeInterval: 20, repeats: true) { [weak self] _ in
|
||||
Task { @MainActor [weak self] in
|
||||
@@ -119,7 +121,7 @@ final class BackgroundSyncManager: ObservableObject {
|
||||
for job in jobs where job.scheduleEnabled && job.scheduleKind != .manual && job.nextRunAt == nil {
|
||||
job.nextRunAt = job.calculateNextRun(after: Date().addingTimeInterval(-1))
|
||||
}
|
||||
try? modelContext.save()
|
||||
saveContext("refreshing automation configuration")
|
||||
}
|
||||
|
||||
private func checkSchedules() {
|
||||
@@ -136,7 +138,7 @@ final class BackgroundSyncManager: ObservableObject {
|
||||
job.nextRunAt = job.calculateNextRun(after: now)
|
||||
}
|
||||
}
|
||||
try? modelContext.save()
|
||||
saveContext("updating scheduled jobs")
|
||||
}
|
||||
|
||||
private func fileChanged(jobID: UUID, path: String) {
|
||||
@@ -150,7 +152,7 @@ final class BackgroundSyncManager: ObservableObject {
|
||||
guard !Task.isCancelled, let self else { return }
|
||||
_ = self.enqueue(jobID: jobID, trigger: .watched)
|
||||
}
|
||||
try? modelContext.save()
|
||||
saveContext("recording file-watch activity")
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
@@ -209,12 +211,12 @@ final class BackgroundSyncManager: ObservableObject {
|
||||
let command = RsyncCommandBuilder.displayCommand(job: job, dryRun: false, executable: executable)
|
||||
let run = SyncRun(job: job, command: command, wasDryRun: false, trigger: trigger)
|
||||
modelContext.insert(run)
|
||||
try? modelContext.save()
|
||||
saveContext("creating run history")
|
||||
|
||||
do {
|
||||
let result = try await runner.run(job: job, dryRun: false)
|
||||
run.output = result.stdout
|
||||
run.errorOutput = result.stderr
|
||||
let result = try await runner.run(job: job, dryRun: false, trigger: trigger)
|
||||
run.output = SyncRun.sanitizedLog(result.stdout)
|
||||
run.errorOutput = SyncRun.sanitizedLog(result.stderr)
|
||||
run.exitCode = Int(result.exitCode)
|
||||
run.wasCancelled = result.wasCancelled
|
||||
run.finishedAt = Date()
|
||||
@@ -222,13 +224,42 @@ final class BackgroundSyncManager: ObservableObject {
|
||||
job.lastExitCode = Int(result.exitCode)
|
||||
job.updatedAt = Date()
|
||||
} catch {
|
||||
run.errorOutput = error.localizedDescription
|
||||
run.errorOutput = SyncRun.sanitizedLog(error.localizedDescription)
|
||||
run.exitCode = -1
|
||||
run.finishedAt = Date()
|
||||
job.lastRunAt = run.finishedAt
|
||||
job.lastExitCode = -1
|
||||
}
|
||||
try? modelContext.save()
|
||||
saveContext("saving run history")
|
||||
pruneHistoryIfNeeded()
|
||||
}
|
||||
|
||||
private func pruneHistoryIfNeeded(force: Bool = false) {
|
||||
let now = Date()
|
||||
if !force, let last = UserDefaults.standard.object(forKey: "lastHistoryPruneAt") as? Date, now.timeIntervalSince(last) < 3600 { return }
|
||||
|
||||
let configuredDays = UserDefaults.standard.integer(forKey: "historyRetentionDays")
|
||||
let days = configuredDays == 0 ? 90 : max(7, min(configuredDays, 3650))
|
||||
let cutoff = now.addingTimeInterval(-TimeInterval(days) * 86_400)
|
||||
|
||||
do {
|
||||
let runs = try modelContext.fetch(FetchDescriptor<SyncRun>())
|
||||
for run in runs where run.finishedAt != nil && run.startedAt < cutoff {
|
||||
modelContext.delete(run)
|
||||
}
|
||||
try modelContext.save()
|
||||
UserDefaults.standard.set(now, forKey: "lastHistoryPruneAt")
|
||||
} catch {
|
||||
lastError = "Could not prune run history: \(error.localizedDescription)"
|
||||
}
|
||||
}
|
||||
|
||||
private func saveContext(_ operation: String) {
|
||||
do {
|
||||
try modelContext.save()
|
||||
} catch {
|
||||
lastError = "Database error while \(operation): \(error.localizedDescription)"
|
||||
}
|
||||
}
|
||||
|
||||
private func fetchJobs() -> [SyncJob] {
|
||||
|
||||
Reference in New Issue
Block a user