diff --git a/example_test.go b/example_test.go index 349089ec..9f0574b3 100644 --- a/example_test.go +++ b/example_test.go @@ -270,6 +270,19 @@ func ExampleScheduler_CustomTime() { // s.CustomTime(mct) } +func ExampleScheduler_CustomTimer() { + s := gocron.NewScheduler(time.UTC) + s.CustomTimer(func(d time.Duration, f func()) *time.Timer { + // force jobs with 1 minute interval to run every second + if d == time.Minute { + d = time.Second + } + return time.AfterFunc(d, f) + }) + // this job will run every 1 second + _, _ = s.Every("1m").Do(task) +} + func ExampleScheduler_Day() { s := gocron.NewScheduler(time.UTC) diff --git a/scheduler.go b/scheduler.go index 75fddf9b..6c249c74 100644 --- a/scheduler.go +++ b/scheduler.go @@ -27,7 +27,8 @@ type Scheduler struct { running bool // represents if the scheduler is running at the moment or not time TimeWrapper // wrapper around time.Time - executor *executor // executes jobs passed via chan + timer func(d time.Duration, f func()) *time.Timer + executor *executor // executes jobs passed via chan tags sync.Map // for storing tags when unique tags is set @@ -55,6 +56,7 @@ func NewScheduler(loc *time.Location) *Scheduler { time: &trueTime{}, executor: &executor, tagsUnique: false, + timer: afterFunc, } } @@ -569,7 +571,7 @@ func (s *Scheduler) runContinuous(job *Job) { s.run(job) } - job.setTimer(time.AfterFunc(next.duration, func() { + job.setTimer(s.timer(next.duration, func() { if !next.dateTime.IsZero() { for { n := s.now().UnixNano() - next.dateTime.UnixNano() @@ -1303,6 +1305,13 @@ func (s *Scheduler) CustomTime(customTimeWrapper TimeWrapper) { s.time = customTimeWrapper } +// CustomTimer takes in a function that mirrors the time.AfterFunc +// This is used to mock the time.AfterFunc function used by the scheduler +// for testing long intervals in a short amount of time. +func (s *Scheduler) CustomTimer(customTimer func(d time.Duration, f func()) *time.Timer) { + s.timer = customTimer +} + func (s *Scheduler) StopBlockingChan() { s.startBlockingStopChanMutex.Lock() if s.startBlockingStopChan != nil { diff --git a/timeHelper.go b/timeHelper.go index f3ce9563..487a7a2a 100644 --- a/timeHelper.go +++ b/timeHelper.go @@ -25,3 +25,9 @@ func (t *trueTime) Unix(sec int64, nsec int64) time.Time { func (t *trueTime) Sleep(d time.Duration) { time.Sleep(d) } + +// afterFunc proxies the time.AfterFunc function. +// This allows it to be mocked for testing. +func afterFunc(d time.Duration, f func()) *time.Timer { + return time.AfterFunc(d, f) +}