package sync import ( "context" "log/slog" "time" "git.mchus.pro/mchus/quoteforge/internal/db" ) // Worker performs background synchronization at regular intervals type Worker struct { service *Service connMgr *db.ConnectionManager interval time.Duration logger *slog.Logger stopCh chan struct{} } // NewWorker creates a new background sync worker func NewWorker(service *Service, connMgr *db.ConnectionManager, interval time.Duration) *Worker { return &Worker{ service: service, connMgr: connMgr, interval: interval, logger: slog.Default(), stopCh: make(chan struct{}), } } // isOnline checks if the database connection is available func (w *Worker) isOnline() bool { return w.connMgr.IsOnline() } // Start begins the background sync loop in a goroutine func (w *Worker) Start(ctx context.Context) { w.logger.Info("starting background sync worker", "interval", w.interval) ticker := time.NewTicker(w.interval) defer ticker.Stop() // Run once immediately w.runSync() for { select { case <-ctx.Done(): w.logger.Info("background sync worker stopped by context") return case <-w.stopCh: w.logger.Info("background sync worker stopped") return case <-ticker.C: w.runSync() } } } // Stop gracefully stops the worker func (w *Worker) Stop() { w.logger.Info("stopping background sync worker") close(w.stopCh) } // runSync performs a single sync iteration func (w *Worker) runSync() { // Check if online if !w.isOnline() { w.logger.Debug("offline, skipping background sync") return } // Push pending changes first pushed, err := w.service.PushPendingChanges() if err != nil { w.logger.Warn("background sync: failed to push pending changes", "error", err) } else if pushed > 0 { w.logger.Info("background sync: pushed pending changes", "count", pushed) } // Then check for new pricelists err = w.service.SyncPricelistsIfNeeded() if err != nil { w.logger.Warn("background sync: failed to sync pricelists", "error", err) } w.logger.Info("background sync cycle completed") }