Skip to content

Commit

Permalink
fix: improve UI performance
Browse files Browse the repository at this point in the history
  • Loading branch information
garethgeorge committed Nov 17, 2023
1 parent 93b2120 commit 8488d46
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 65 deletions.
6 changes: 4 additions & 2 deletions internal/orchestrator/orchestrator.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ func (o *Orchestrator) Run(mainCtx context.Context) error {

// runImmutable is a helper function for Run() that runs the orchestration loop with a single version of the config.
func (o *Orchestrator) runVersion(mainCtx context.Context, config *v1.Config) bool {
lock := sync.Mutex{}
var lock sync.Mutex
ctx, cancel := context.WithCancel(mainCtx)

var wg sync.WaitGroup
Expand All @@ -140,7 +140,9 @@ func (o *Orchestrator) runVersion(mainCtx context.Context, config *v1.Config) bo
defer wg.Done()
select {
case <-ctx.Done():
timer.Stop()
if !timer.Stop() {
<-timer.C
}
zap.L().Debug("cancelled scheduled (but not running) task, orchestrator context is cancelled.", zap.String("task", t.Name()))
return
case <-timer.C:
Expand Down
63 changes: 6 additions & 57 deletions internal/orchestrator/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,6 @@ type RepoOrchestrator struct {

repoConfig *v1.Repo
repo *restic.Repo

// TODO: decide if snapshot caching is a good idea. We gain performance but
// increase background memory use by a small amount at all times (probably on the order of 1MB).
snapshotsMu sync.Mutex // enable very fast snapshot access IF no update is required.
snapshotsResetTimer *time.Timer
snapshots []*restic.Snapshot
}

func newRepoOrchestrator(repoConfig *v1.Repo, repo *restic.Repo) *RepoOrchestrator {
Expand All @@ -34,64 +28,26 @@ func newRepoOrchestrator(repoConfig *v1.Repo, repo *restic.Repo) *RepoOrchestrat
}
}

func (r *RepoOrchestrator) updateSnapshotsIfNeeded(ctx context.Context, force bool) error {
if r.snapshots != nil {
return nil
}

if r.snapshotsResetTimer != nil {
if !r.snapshotsResetTimer.Stop() {
<-r.snapshotsResetTimer.C
}
}

r.snapshotsResetTimer = time.AfterFunc(10 * time.Minute, func() {
r.snapshotsMu.Lock()
defer r.snapshotsMu.Unlock()
r.snapshots = nil
})

if r.snapshots != nil {
return nil
}


startTime := time.Now()

func (r *RepoOrchestrator) Snapshots(ctx context.Context) ([]*restic.Snapshot, error) {
snapshots, err := r.repo.Snapshots(ctx, restic.WithPropagatedEnvVars(restic.EnvToPropagate...), restic.WithFlags("--latest", "1000"))
if err != nil {
return fmt.Errorf("failed to update snapshots: %w", err)
return nil, fmt.Errorf("restic.Snapshots: %w", err)
}

sort.SliceStable(snapshots, func(i, j int) bool {
return snapshots[i].UnixTimeMs() < snapshots[j].UnixTimeMs()
})
r.snapshots = snapshots

zap.L().Debug("updated snapshots", zap.String("repo", r.repoConfig.Id), zap.Duration("duration", time.Since(startTime)))

return nil
}

func (r *RepoOrchestrator) Snapshots(ctx context.Context) ([]*restic.Snapshot, error) {
r.snapshotsMu.Lock()
defer r.snapshotsMu.Unlock()
if err := r.updateSnapshotsIfNeeded(ctx, false); err != nil {
return nil, err
}

return r.snapshots, nil
return snapshots, nil
}

func (r *RepoOrchestrator) SnapshotsForPlan(ctx context.Context, plan *v1.Plan) ([]*restic.Snapshot, error) {
r.snapshotsMu.Lock()
defer r.snapshotsMu.Unlock()

if err := r.updateSnapshotsIfNeeded(ctx, false); err != nil {
snapshots, err := r.Snapshots(ctx)
if err != nil {
return nil, err
}

return filterSnapshotsForPlan(r.snapshots, plan), nil
return filterSnapshotsForPlan(snapshots, plan), nil
}

func (r *RepoOrchestrator) Backup(ctx context.Context, plan *v1.Plan, progressCallback func(event *restic.BackupProgressEntry)) (*restic.BackupProgressEntry, error) {
Expand Down Expand Up @@ -123,14 +79,7 @@ func (r *RepoOrchestrator) Backup(ctx context.Context, plan *v1.Plan, progressCa
return nil, fmt.Errorf("failed to backup: %w", err)
}

// Reset snapshots since a new backup has been added.
r.snapshotsMu.Lock()
r.snapshots = nil
r.snapshotsMu.Unlock()

zap.L().Debug("Backup completed", zap.String("repo", r.repoConfig.Id), zap.Duration("duration", time.Since(startTime)))


return summary, nil
}

Expand Down
28 changes: 22 additions & 6 deletions webui/src/components/OperationList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,6 @@ export const OperationList = ({
}: React.PropsWithoutRef<{ operations: EOperation[] }>) => {
operations.sort((a, b) => b.parsedTime - a.parsedTime);

const elems = operations.map((operation) => (
<OperationRow operation={operation} />
));

if (operations.length === 0) {
return (
<Empty
Expand All @@ -38,6 +34,11 @@ export const OperationList = ({
renderItem={(item, index) => (
<OperationRow key={item.parsedId} operation={item} />
)}
pagination={
operations.length > 50
? { position: "both", align: "center", defaultPageSize: 50 }
: {}
}
/>
);
};
Expand Down Expand Up @@ -68,7 +69,10 @@ export const OperationRow = ({
const backupOp = operation.operationBackup;
let desc = `Backup at ${formatTime(operation.unixTimeStartMs!)}`;
if (operation.status !== OperationStatus.STATUS_INPROGRESS) {
desc += ` and finished at ${formatTime(operation.unixTimeEndMs!)}`;
desc += ` completed in ${formatDuration(
parseInt(operation.unixTimeEndMs!) -
parseInt(operation.unixTimeStartMs!)
)}`;
} else {
desc += " and is still running.";
}
Expand Down Expand Up @@ -273,5 +277,17 @@ const formatTime = (time: number | string) => {
}
const d = new Date();
d.setTime(time);
return d.toLocaleString();
return d.toISOString();
};

const formatDuration = (ms: number) => {
const seconds = Math.floor(ms / 100) / 10;
const minutes = Math.floor(seconds / 60);
const hours = Math.floor(minutes / 60);
if (hours === 0 && minutes === 0) {
return `${seconds % 60}s`;
} else if (hours === 0) {
return `${minutes}m${seconds % 60}s`;
}
return `${hours}h${minutes % 60}m${seconds % 60}s`;
};

0 comments on commit 8488d46

Please sign in to comment.