package backgroundtask import ( "fmt" "io" "sync" "sync/atomic" "time" ) // Stats provides observability into the runner's operation. // All methods are thread-safe and can be called concurrently. type Stats struct { mu sync.RWMutex workCycles atomic.Int64 // Total number of work cycles completed lastStart time.Time // Time when the last work cycle started lastFinish time.Time // Time when the last work cycle finished lastErr error // Last error returned from work function maxConcurrent atomic.Int32 // Maximum concurrent work attempts (should always be 1) currentConcurrent atomic.Int32 // Current concurrent work executions } // WorkCycles returns the total number of work cycles completed. func (s *Stats) WorkCycles() int64 { return s.workCycles.Load() } // LastStart returns the time when the last work cycle started. func (s *Stats) LastStart() time.Time { s.mu.RLock() defer s.mu.RUnlock() return s.lastStart } // LastFinish returns the time when the last work cycle finished. func (s *Stats) LastFinish() time.Time { s.mu.RLock() defer s.mu.RUnlock() return s.lastFinish } // LastErr returns the last error returned from the work function. func (s *Stats) LastErr() error { s.mu.RLock() defer s.mu.RUnlock() return s.lastErr } // MaxConcurrent returns the maximum number of concurrent work executions observed. // This should always be 1 if the runner is working correctly. func (s *Stats) MaxConcurrent() int32 { return s.maxConcurrent.Load() } // CurrentConcurrent returns the current number of concurrent work executions. // This should be 0 or 1. func (s *Stats) CurrentConcurrent() int32 { return s.currentConcurrent.Load() } // incrementWorkCycles increments the work cycle counter. func (s *Stats) incrementWorkCycles() { s.workCycles.Add(1) } // setLastStart updates the last start time. func (s *Stats) setLastStart(t time.Time) { s.mu.Lock() defer s.mu.Unlock() s.lastStart = t } // setLastFinish updates the last finish time. func (s *Stats) setLastFinish(t time.Time) { s.mu.Lock() defer s.mu.Unlock() s.lastFinish = t } // setLastErr updates the last error. func (s *Stats) setLastErr(err error) { s.mu.Lock() defer s.mu.Unlock() s.lastErr = err } // enterWork marks the beginning of a work cycle and tracks concurrency. func (s *Stats) enterWork() { current := s.currentConcurrent.Add(1) // Update max concurrent if needed for { max := s.maxConcurrent.Load() if current <= max { break } if s.maxConcurrent.CompareAndSwap(max, current) { break } } } // exitWork marks the end of a work cycle. func (s *Stats) exitWork() { s.currentConcurrent.Add(-1) } // Reset clears all statistics. Used primarily for testing. func (s *Stats) Reset() { s.mu.Lock() defer s.mu.Unlock() s.workCycles.Store(0) s.lastStart = time.Time{} s.lastFinish = time.Time{} s.lastErr = nil s.maxConcurrent.Store(0) s.currentConcurrent.Store(0) } // Print writes a formatted representation of all statistics to the provided writer. // The output includes work cycles, timing information, error status, and concurrency metrics. func (s *Stats) Print(w io.Writer) { s.mu.RLock() lastStart := s.lastStart lastFinish := s.lastFinish lastErr := s.lastErr s.mu.RUnlock() workCycles := s.workCycles.Load() maxConcurrent := s.maxConcurrent.Load() currentConcurrent := s.currentConcurrent.Load() fmt.Fprintf(w, "╭─────────────────────────────────────────────╮\n") fmt.Fprintf(w, "│ Background Task Runner Stats │\n") fmt.Fprintf(w, "├─────────────────────────────────────────────┤\n") fmt.Fprintf(w, "│ Work Cycles: %-23d │\n", workCycles) fmt.Fprintf(w, "│ Current Concurrent: %-23d │\n", currentConcurrent) fmt.Fprintf(w, "│ Max Concurrent: %-23d │\n", maxConcurrent) fmt.Fprintf(w, "├─────────────────────────────────────────────┤\n") // Format timing information if !lastStart.IsZero() { fmt.Fprintf(w, "│ Last Start: %-30s │\n", lastStart.Format("2006-01-02 15:04:05.000")) } else { fmt.Fprintf(w, "│ Last Start: %-30s │\n", "Never") } if !lastFinish.IsZero() { fmt.Fprintf(w, "│ Last Finish: %-30s │\n", lastFinish.Format("2006-01-02 15:04:05.000")) if !lastStart.IsZero() { duration := lastFinish.Sub(lastStart) fmt.Fprintf(w, "│ Duration: %-30s │\n", duration.String()) } } else { fmt.Fprintf(w, "│ Last Finish: %-30s │\n", "Never") } fmt.Fprintf(w, "├─────────────────────────────────────────────┤\n") // Format error information if lastErr != nil { errStr := lastErr.Error() if len(errStr) > 30 { errStr = errStr[:27] + "..." } fmt.Fprintf(w, "│ Last Error: %-30s │\n", errStr) } else { fmt.Fprintf(w, "│ Last Error: %-30s │\n", "None") } fmt.Fprintf(w, "╰─────────────────────────────────────────────╯\n") }