package service import ( "context" "log" "sync" "time" "github.com/jackc/pgx/v5/pgxpool" ) // CronJob defines a scheduled task. type CronJob struct { Name string Interval time.Duration Handler func(ctx context.Context, pool *pgxpool.Pool) error running bool } // CronScheduler manages periodic jobs. type CronScheduler struct { jobs []*CronJob mu sync.Mutex ctx context.Context cancel context.CancelFunc } // NewCronScheduler creates a new scheduler. func NewCronScheduler() *CronScheduler { ctx, cancel := context.WithCancel(context.Background()) return &CronScheduler{ctx: ctx, cancel: cancel} } // Register adds a job to the scheduler. func (s *CronScheduler) Register(job *CronJob) { s.mu.Lock() defer s.mu.Unlock() s.jobs = append(s.jobs, job) } // Start begins running all registered jobs. func (s *CronScheduler) Start(pool *pgxpool.Pool) { for _, job := range s.jobs { go s.runJob(job, pool) } log.Printf("cron: started %d jobs", len(s.jobs)) } // Stop cancels all running jobs. func (s *CronScheduler) Stop() { s.cancel() } func (s *CronScheduler) runJob(job *CronJob, pool *pgxpool.Pool) { ticker := time.NewTicker(job.Interval) defer ticker.Stop() for { select { case <-s.ctx.Done(): return case <-ticker.C: if err := job.Handler(s.ctx, pool); err != nil { log.Printf("cron: %s error: %v", job.Name, err) } } } }