package service import ( "context" "log" "sync" "time" ) // DeferredService provides deferred batch update functionality type DeferredService struct { accountRepo AccountRepository timingWheel *TimingWheelService interval time.Duration lastUsedUpdates sync.Map } // NewDeferredService creates a new DeferredService instance func NewDeferredService(accountRepo AccountRepository, timingWheel *TimingWheelService, interval time.Duration) *DeferredService { return &DeferredService{ accountRepo: accountRepo, timingWheel: timingWheel, interval: interval, } } // Start starts the deferred service func (s *DeferredService) Start() { s.timingWheel.ScheduleRecurring("deferred:last_used", s.interval, s.flushLastUsed) log.Printf("[DeferredService] Started (interval: %v)", s.interval) } // Stop stops the deferred service func (s *DeferredService) Stop() { s.timingWheel.Cancel("deferred:last_used") s.flushLastUsed() log.Printf("[DeferredService] Service stopped") } func (s *DeferredService) ScheduleLastUsedUpdate(accountID int64) { s.lastUsedUpdates.Store(accountID, time.Now()) } func (s *DeferredService) flushLastUsed() { updates := make(map[int64]time.Time) s.lastUsedUpdates.Range(func(key, value any) bool { id, ok := key.(int64) if !ok { return true } ts, ok := value.(time.Time) if !ok { return true } updates[id] = ts s.lastUsedUpdates.Delete(key) return true }) if len(updates) == 0 { return } ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() if err := s.accountRepo.BatchUpdateLastUsed(ctx, updates); err != nil { log.Printf("[DeferredService] BatchUpdateLastUsed failed (%d accounts): %v", len(updates), err) for id, ts := range updates { s.lastUsedUpdates.Store(id, ts) } } else { log.Printf("[DeferredService] BatchUpdateLastUsed flushed %d accounts", len(updates)) } }