Add live activity progress and logs
This commit is contained in:
@@ -221,20 +221,33 @@ func (s *Service) execute(ctx context.Context, run model.Run) model.Run {
|
||||
if !ok {
|
||||
return failed(run, "validation", "repository no longer exists")
|
||||
}
|
||||
live := run
|
||||
appendLiveLog(&live, strings.ToUpper(run.TaskType)+" wird vorbereitet")
|
||||
s.updateActive(live)
|
||||
mounted, err := s.mounts.Prepare(ctx, repo)
|
||||
if err != nil {
|
||||
return failedError(run, err)
|
||||
failedRun := failedError(run, err)
|
||||
appendLiveLog(&live, "Vorbereitung fehlgeschlagen: "+err.Error())
|
||||
failedRun.LiveLog = live.LiveLog
|
||||
return failedRun
|
||||
}
|
||||
defer s.mounts.Cleanup(context.Background(), mounted)
|
||||
appendLiveLog(&live, "Repository bereit; Restic "+run.TaskType+" läuft")
|
||||
s.updateActive(live)
|
||||
if run.TaskType == "check" {
|
||||
err = s.restic.Check(ctx, mounted.Repository)
|
||||
} else {
|
||||
err = s.restic.Prune(ctx, mounted.Repository)
|
||||
}
|
||||
if err != nil {
|
||||
return failedError(run, err)
|
||||
failedRun := failedError(run, err)
|
||||
appendLiveLog(&live, strings.ToUpper(run.TaskType)+" fehlgeschlagen: "+err.Error())
|
||||
failedRun.LiveLog = live.LiveLog
|
||||
return failedRun
|
||||
}
|
||||
run.Status, run.Message = "success", run.TaskType+" completed"
|
||||
appendLiveLog(&live, strings.ToUpper(run.TaskType)+" abgeschlossen")
|
||||
run.LiveLog = live.LiveLog
|
||||
return run
|
||||
}
|
||||
|
||||
@@ -248,6 +261,9 @@ func (s *Service) executeBackup(ctx context.Context, run model.Run) (result mode
|
||||
if !ok {
|
||||
return failed(run, "validation", "repository no longer exists")
|
||||
}
|
||||
live := run
|
||||
appendLiveLog(&live, "Backup wird vorbereitet")
|
||||
s.updateActive(live)
|
||||
mounted, err := s.mounts.Prepare(ctx, repo)
|
||||
if err != nil {
|
||||
return failedError(run, err)
|
||||
@@ -277,10 +293,36 @@ func (s *Service) executeBackup(ctx context.Context, run model.Run) (result mode
|
||||
return failed(run, "source", "source unavailable: "+path)
|
||||
}
|
||||
}
|
||||
summary, err := s.restic.Backup(ctx, mounted.Repository, job, prepared.Sources)
|
||||
appendLiveLog(&live, fmt.Sprintf("Restic-Backup gestartet: %d Quelle(n)", len(prepared.Sources)))
|
||||
s.updateActive(live)
|
||||
lastLoggedPercent := -5
|
||||
started := time.Now()
|
||||
summary, err := s.restic.Backup(ctx, mounted.Repository, job, prepared.Sources, func(progress restic.Progress) {
|
||||
live.ProgressPercent = progress.PercentDone * 100
|
||||
live.ProgressBytes, live.ProgressTotal = progress.BytesDone, progress.TotalBytes
|
||||
live.ProgressFiles, live.ProgressFileTotal = progress.FilesDone, progress.TotalFiles
|
||||
live.SecondsRemaining = progress.SecondsRemaining
|
||||
if elapsed := time.Since(started).Seconds(); elapsed > 0 {
|
||||
live.BytesPerSecond = float64(progress.BytesDone) / elapsed
|
||||
}
|
||||
if len(progress.CurrentFiles) > 0 {
|
||||
live.CurrentFile = progress.CurrentFiles[len(progress.CurrentFiles)-1]
|
||||
}
|
||||
percent := int(live.ProgressPercent)
|
||||
if percent >= lastLoggedPercent+5 {
|
||||
appendLiveLog(&live, fmt.Sprintf("Fortschritt: %.1f%%, %d/%d Dateien, %s/%s", live.ProgressPercent, live.ProgressFiles, live.ProgressFileTotal, formatBytes(live.ProgressBytes), formatBytes(live.ProgressTotal)))
|
||||
lastLoggedPercent = percent - percent%5
|
||||
}
|
||||
s.updateActive(live)
|
||||
})
|
||||
if err != nil {
|
||||
return failedError(run, err)
|
||||
appendLiveLog(&live, "Backup fehlgeschlagen: "+err.Error())
|
||||
failedRun := failedError(run, err)
|
||||
failedRun.LiveLog = live.LiveLog
|
||||
return failedRun
|
||||
}
|
||||
appendLiveLog(&live, "Backup-Daten übertragen; Aufbewahrung wird angewendet")
|
||||
s.updateActive(live)
|
||||
if err := s.restic.Forget(ctx, mounted.Repository, job); err != nil {
|
||||
run.Status, run.Message, run.ErrorCode = "warning", "backup succeeded but retention failed: "+err.Error(), "repository"
|
||||
} else {
|
||||
@@ -288,10 +330,36 @@ func (s *Service) executeBackup(ctx context.Context, run model.Run) (result mode
|
||||
}
|
||||
run.SnapshotID, run.BytesAdded, run.FilesNew, run.FilesChanged = summary.SnapshotID, summary.DataAdded, summary.FilesNew, summary.FilesChanged
|
||||
run.BytesProcessed, run.FilesProcessed = summary.TotalBytesProcessed, summary.TotalFilesProcessed
|
||||
run.ProgressPercent, run.ProgressBytes, run.ProgressTotal = 100, live.ProgressBytes, live.ProgressTotal
|
||||
run.ProgressFiles, run.ProgressFileTotal = live.ProgressFiles, live.ProgressFileTotal
|
||||
run.BytesPerSecond, run.SecondsRemaining, run.CurrentFile = live.BytesPerSecond, 0, live.CurrentFile
|
||||
appendLiveLog(&live, "Backup abgeschlossen")
|
||||
run.LiveLog = live.LiveLog
|
||||
return run
|
||||
}
|
||||
|
||||
func (s *Service) updateActive(run model.Run) {
|
||||
s.queue.UpdateActive(run.ID, func(active *model.Run) {
|
||||
active.ProgressPercent, active.ProgressBytes, active.ProgressTotal = run.ProgressPercent, run.ProgressBytes, run.ProgressTotal
|
||||
active.ProgressFiles, active.ProgressFileTotal = run.ProgressFiles, run.ProgressFileTotal
|
||||
active.BytesPerSecond, active.SecondsRemaining = run.BytesPerSecond, run.SecondsRemaining
|
||||
active.CurrentFile = run.CurrentFile
|
||||
active.LiveLog = append([]string(nil), run.LiveLog...)
|
||||
})
|
||||
}
|
||||
|
||||
func appendLiveLog(run *model.Run, message string) {
|
||||
line := time.Now().Format("15:04:05") + " " + strings.ReplaceAll(strings.TrimSpace(message), "\n", " ")
|
||||
run.LiveLog = append(run.LiveLog, line)
|
||||
if len(run.LiveLog) > 100 {
|
||||
run.LiveLog = run.LiveLog[len(run.LiveLog)-100:]
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) executeRestore(ctx context.Context, run model.Run) model.Run {
|
||||
live := run
|
||||
appendLiveLog(&live, "Restore wird vorbereitet")
|
||||
s.updateActive(live)
|
||||
parts := strings.Split(run.JobID, "\x00")
|
||||
if len(parts) < 4 {
|
||||
return failed(run, "internal", "invalid restore payload")
|
||||
@@ -302,17 +370,30 @@ func (s *Service) executeRestore(ctx context.Context, run model.Run) model.Run {
|
||||
}
|
||||
task := model.RestoreTask{SchemaVersion: model.SchemaVersion, ID: run.ID, RepositoryID: parts[0], SnapshotID: parts[1], Target: parts[2], InPlace: parts[3] == "true", Confirmed: true, Includes: parts[4:]}
|
||||
if err := os.MkdirAll(task.Target, 0750); err != nil {
|
||||
return failedError(run, err)
|
||||
failedRun := failedError(run, err)
|
||||
appendLiveLog(&live, "Restore-Ziel konnte nicht vorbereitet werden: "+err.Error())
|
||||
failedRun.LiveLog = live.LiveLog
|
||||
return failedRun
|
||||
}
|
||||
mounted, err := s.mounts.Prepare(ctx, repo)
|
||||
if err != nil {
|
||||
return failedError(run, err)
|
||||
failedRun := failedError(run, err)
|
||||
appendLiveLog(&live, "Repository konnte nicht vorbereitet werden: "+err.Error())
|
||||
failedRun.LiveLog = live.LiveLog
|
||||
return failedRun
|
||||
}
|
||||
defer s.mounts.Cleanup(context.Background(), mounted)
|
||||
appendLiveLog(&live, "Restic stellt den Snapshot wieder her")
|
||||
s.updateActive(live)
|
||||
if err := s.restic.Restore(ctx, mounted.Repository, task); err != nil {
|
||||
return failedError(run, err)
|
||||
failedRun := failedError(run, err)
|
||||
appendLiveLog(&live, "Restore fehlgeschlagen: "+err.Error())
|
||||
failedRun.LiveLog = live.LiveLog
|
||||
return failedRun
|
||||
}
|
||||
run.Status, run.Message, run.JobID = "success", "restore completed", ""
|
||||
appendLiveLog(&live, "Restore abgeschlossen")
|
||||
run.LiveLog = live.LiveLog
|
||||
return run
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user