diff --git a/internal/db/interface.go b/internal/db/interface.go index 447f64cba..32c79cc49 100644 --- a/internal/db/interface.go +++ b/internal/db/interface.go @@ -19,7 +19,12 @@ type DBService interface { suture.Service // Starts maintenance asynchronously, if not already running - StartMaintenance() + // Returns a channel that will receive the result when the requested maintenance finishes + StartMaintenance() <-chan error + + // Returns the last time database maintenance completed + // This will return time zero when database maintenance has never completed successfully. + LastMaintenanceTime() time.Time } type DB interface { diff --git a/internal/db/sqlite/db_service.go b/internal/db/sqlite/db_service.go index 448b084cd..4dc817771 100644 --- a/internal/db/sqlite/db_service.go +++ b/internal/db/sqlite/db_service.go @@ -39,7 +39,7 @@ type Service struct { sdb *DB maintenanceInterval time.Duration internalMeta *db.Typed - start chan struct{} + start chan chan error } func (s *Service) String() string { @@ -51,15 +51,17 @@ func newService(sdb *DB, maintenanceInterval time.Duration) *Service { sdb: sdb, maintenanceInterval: maintenanceInterval, internalMeta: db.NewTyped(sdb, internalMetaPrefix), - start: make(chan struct{}), + start: make(chan chan error), } } -func (s *Service) StartMaintenance() { +func (s *Service) StartMaintenance() <-chan error { + finishChan := make(chan error, 1) select { - case s.start <- struct{}{}: + case s.start <- finishChan: default: } + return finishChan } func (s *Service) Serve(ctx context.Context) error { @@ -80,14 +82,20 @@ func (s *Service) Serve(ctx context.Context) error { } for { + var finishChan chan error select { case <-ctx.Done(): return ctx.Err() case <-timer.C: - case <-s.start: + case finishChan = <-s.start: } - if err := s.periodic(ctx); err != nil { + err := s.periodic(ctx) + if finishChan != nil { + finishChan <- err + } + + if err != nil { return wrap(err) } @@ -100,6 +108,11 @@ func (s *Service) Serve(ctx context.Context) error { } } +func (s *Service) LastMaintenanceTime() time.Time { + lastMaint, _, _ := s.internalMeta.Time(lastMaintKey) + return lastMaint +} + func (s *Service) periodic(ctx context.Context) error { t0 := time.Now() slog.DebugContext(ctx, "Periodic start") diff --git a/lib/syncthing/syncthing.go b/lib/syncthing/syncthing.go index 21b186c2f..1f3664285 100644 --- a/lib/syncthing/syncthing.go +++ b/lib/syncthing/syncthing.go @@ -116,8 +116,14 @@ func (a *App) Start() error { } // StartMaintenance asynchronously triggers database maintenance to start. -func (a *App) StartMaintenance() { - a.dbService.StartMaintenance() +func (a *App) StartMaintenance() <-chan error { + return a.dbService.StartMaintenance() +} + +// LastMaintenanceTime returns the last time database maintenance completed successfully +// This will return time zero when database maintenance has never completed successfully. +func (a *App) LastMaintenanceTime() time.Time { + return a.dbService.LastMaintenanceTime() } func (a *App) startup() error {