// Package scheduler runs a function on a fixed interval with an immediate // first execution, until the context is cancelled. package scheduler import ( "context" "time" ) // Scheduler triggers a run function periodically. type Scheduler struct { interval time.Duration run func(ctx context.Context) error } // New creates a Scheduler that calls run immediately and then every // interval. An interval <= 0 means run once and stop. func New(interval time.Duration, run func(ctx context.Context) error) *Scheduler { return &Scheduler{interval: interval, run: run} } // Run executes run immediately and then every interval until ctx is // cancelled. A run error stops the loop and is returned, except when the // context was cancelled (graceful shutdown is not an error). func (s *Scheduler) Run(ctx context.Context) error { if err := ctx.Err(); err != nil { return nil } if err := s.run(ctx); err != nil { if ctx.Err() != nil { return nil } return err } if s.interval <= 0 { return nil } ticker := time.NewTicker(s.interval) defer ticker.Stop() for { select { case <-ctx.Done(): return nil case <-ticker.C: if err := s.run(ctx); err != nil { if ctx.Err() != nil { return nil } return err } } } }