diff --git a/README.md b/README.md index ce2ca896..7015f170 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ See also these two great articles: If you want to chat, you can find us at Slack! [](https://gophers.slack.com/archives/CQ7T0T1FW) -# Examples: +## Examples: ```go package main @@ -71,7 +71,6 @@ func main() { tag1 := []string{"tag1"} tag2 := []string{"tag2"} - s2.Every(1).Week().SetTag(tag1).Do(task) s2.Every(1).Week().SetTag(tag2).Do(task) @@ -89,13 +88,15 @@ func main() { s2.Every(1).Wednesday().At("1:01").Do(task) // Begin job at a specific date/time. - // Attention: scheduler timezone has precedence over job's timezone! t := time.Date(2019, time.November, 10, 15, 0, 0, 0, time.UTC) s2.Every(1).Hour().StartAt(t).Do(task) - // use .StartImmediately() to run job upon scheduler start - s2.Every(1).Hour().StartImmediately().Do(task) + // Delay start of job + s2.Every(1).Hour().StartAt(time.Now().Add(time.Duration(1 * time.Hour)).Do(task) + // Deprecated: Jobs start immediately by default + // use StartImmediately() to run job upon scheduler start + s2.Every(1).Hour().StartImmediately().Do(task) // NextRun gets the next running time _, time := s2.NextRun() diff --git a/example_test.go b/example_test.go index 5d2e7c9e..681622ec 100644 --- a/example_test.go +++ b/example_test.go @@ -20,9 +20,10 @@ func ExampleScheduler_StartBlocking() { func ExampleScheduler_StartAsync() { s := gocron.NewScheduler(time.UTC) _, _ = s.Every(3).Seconds().Do(task) - <-s.StartAsync() + s.StartAsync() } +// Deprecated: All jobs start immediately by default unless set to a specific date or time func ExampleScheduler_StartImmediately() { s := gocron.NewScheduler(time.UTC) _, _ = s.Every(1).Hour().StartImmediately().Do(task) diff --git a/job.go b/job.go index 2d0b52d7..ade04cf2 100644 --- a/job.go +++ b/job.go @@ -36,12 +36,13 @@ type runConfig struct { // NewJob creates a new Job with the provided interval func NewJob(interval uint64) *Job { return &Job{ - interval: jobInterval(interval), - lastRun: time.Time{}, - nextRun: time.Time{}, - funcs: make(map[string]interface{}), - fparams: make(map[string][]interface{}), - tags: []string{}, + interval: jobInterval(interval), + lastRun: time.Time{}, + nextRun: time.Time{}, + funcs: make(map[string]interface{}), + fparams: make(map[string][]interface{}), + tags: []string{}, + startsImmediately: true, } } diff --git a/scheduler.go b/scheduler.go index f79646c1..b7b02eeb 100644 --- a/scheduler.go +++ b/scheduler.go @@ -91,15 +91,17 @@ func (s *Scheduler) scheduleNextRun(job *Job) { defer job.Unlock() now := s.time.Now(s.loc) - if job.startsImmediately { - job.nextRun = now - job.startsImmediately = false - return + if job.neverRan() { + if !job.nextRun.IsZero() { + return // scheduled for future run and should skip scheduling + } + // default is for jobs to start immediately unless scheduled at a specific time or day + if job.startsImmediately { + job.nextRun = now + return + } } - if job.neverRan() && !job.nextRun.IsZero() { - return // scheduled for future run and should skip scheduling - } job.lastRun = now durationToNextRun := s.durationToNextRun(job) @@ -422,6 +424,7 @@ func (s *Scheduler) At(t string) *Scheduler { } // save atTime start as duration from midnight j.atTime = time.Duration(hour)*time.Hour + time.Duration(min)*time.Minute + time.Duration(sec)*time.Second + j.startsImmediately = false return s } @@ -434,11 +437,14 @@ func (s *Scheduler) SetTag(t []string) *Scheduler { // StartAt schedules the next run of the Job func (s *Scheduler) StartAt(t time.Time) *Scheduler { - s.getCurrentJob().nextRun = t + job := s.getCurrentJob() + job.nextRun = t + job.startsImmediately = false return s } // StartImmediately sets the Jobs next run as soon as the scheduler starts +// Deprecated: Jobs start immediately by default unless a specific start day or time is set func (s *Scheduler) StartImmediately() *Scheduler { job := s.getCurrentJob() job.startsImmediately = true @@ -520,7 +526,9 @@ func (s *Scheduler) Month(dayOfTheMonth int) *Scheduler { // Months sets the unit with months func (s *Scheduler) Months(dayOfTheMonth int) *Scheduler { - s.getCurrentJob().dayOfTheMonth = dayOfTheMonth + job := s.getCurrentJob() + job.dayOfTheMonth = dayOfTheMonth + job.startsImmediately = false s.setUnit(months) return s } @@ -532,7 +540,9 @@ func (s *Scheduler) Months(dayOfTheMonth int) *Scheduler { // Weekday sets the start with a specific weekday weekday func (s *Scheduler) Weekday(startDay time.Weekday) *Scheduler { - s.getCurrentJob().scheduledWeekday = &startDay + job := s.getCurrentJob() + job.scheduledWeekday = &startDay + job.startsImmediately = false s.setUnit(weeks) return s } diff --git a/scheduler_test.go b/scheduler_test.go index c4840a36..52188f6b 100644 --- a/scheduler_test.go +++ b/scheduler_test.go @@ -53,7 +53,7 @@ func TestExecutionSeconds(t *testing.T) { var ( executions []int64 interval uint64 = 2 - expectedExecutions = 3 + expectedExecutions = 4 ) runTime := time.Duration(6 * time.Second) @@ -135,22 +135,50 @@ func TestAtFuture(t *testing.T) { assert.Equal(t, false, shouldBeFalse, "Day job was not expected to run as it was in the future") } -func schedulerForNextWeekdayEveryNTimes(weekday time.Weekday, n uint64, s *Scheduler) *Scheduler { +func schedulerForNextOrPreviousWeekdayEveryNTimes(weekday time.Weekday, next bool, n uint64, s *Scheduler) *Scheduler { switch weekday { case time.Monday: - s = s.Every(n).Tuesday() + if next { + s = s.Every(n).Tuesday() + } else { + s = s.Every(n).Sunday() + } case time.Tuesday: - s = s.Every(n).Wednesday() + if next { + s = s.Every(n).Wednesday() + } else { + s = s.Every(n).Monday() + } case time.Wednesday: - s = s.Every(n).Thursday() + if next { + s = s.Every(n).Thursday() + } else { + s = s.Every(n).Tuesday() + } case time.Thursday: - s = s.Every(n).Friday() + if next { + s = s.Every(n).Friday() + } else { + s = s.Every(n).Wednesday() + } case time.Friday: - s = s.Every(n).Saturday() + if next { + s = s.Every(n).Saturday() + } else { + s = s.Every(n).Thursday() + } case time.Saturday: - s = s.Every(n).Sunday() + if next { + s = s.Every(n).Sunday() + } else { + s = s.Every(n).Friday() + } case time.Sunday: - s = s.Every(n).Monday() + if next { + s = s.Every(n).Monday() + } else { + s = s.Every(n).Saturday() + } } return s } @@ -159,23 +187,7 @@ func TestWeekdayBeforeToday(t *testing.T) { now := time.Now().In(time.UTC) s := NewScheduler(time.UTC) - // Schedule job at day before - switch now.Weekday() { - case time.Monday: - s = s.Every(1).Sunday() - case time.Tuesday: - s = s.Every(1).Monday() - case time.Wednesday: - s = s.Every(1).Tuesday() - case time.Thursday: - s = s.Every(1).Wednesday() - case time.Friday: - s = s.Every(1).Thursday() - case time.Saturday: - s = s.Every(1).Friday() - case time.Sunday: - s = s.Every(1).Saturday() - } + s = schedulerForNextOrPreviousWeekdayEveryNTimes(now.Weekday(), false, 1, s) weekJob, _ := s.Do(task) s.scheduleNextRun(weekJob) sixDaysFromNow := now.AddDate(0, 0, 6) @@ -188,7 +200,7 @@ func TestWeekdayAt(t *testing.T) { t.Run("asserts weekday scheduling starts at the current week", func(t *testing.T) { s := NewScheduler(time.UTC) now := time.Now().UTC() - s = schedulerForNextWeekdayEveryNTimes(now.Weekday(), 1, s) + s = schedulerForNextOrPreviousWeekdayEveryNTimes(now.Weekday(), true, 1, s) weekdayJob, _ := s.Do(task) s.scheduleNextRun(weekdayJob) @@ -386,7 +398,7 @@ func TestScheduler_StartAt(t *testing.T) { job, _ = scheduler.Every(3).Seconds().Do(func() {}) scheduler.scheduleNextRun(job) _, nextRun = scheduler.NextRun() - assert.Equal(t, now.Add(time.Second*3).Second(), nextRun.Second()) + assert.Equal(t, now.Second(), nextRun.Second()) } func TestScheduler_CalculateNextRun(t *testing.T) {