package worker import ( "context" "time" ) type Job interface { Name() string Run(context.Context) error } type Logger func(format string, args ...any) type Runner struct { jobs []Job interval time.Duration logger Logger } func NewRunner(jobs []Job, interval time.Duration, logger Logger) *Runner { return &Runner{ jobs: append([]Job(nil), jobs...), interval: interval, logger: logger, } } func (r *Runner) Start(ctx context.Context) { if r == nil { return } go func() { r.runOnce(ctx) if ctx.Err() != nil || r.interval <= 0 { return } ticker := time.NewTicker(r.interval) defer ticker.Stop() for { select { case <-ctx.Done(): return case <-ticker.C: r.runOnce(ctx) } } }() } func (r *Runner) runOnce(ctx context.Context) { for _, job := range r.jobs { if ctx.Err() != nil { return } if job == nil { continue } if err := job.Run(ctx); err != nil && ctx.Err() == nil && r.logger != nil { r.logger("%s: %v", job.Name(), err) } } }