Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

start jobs immediately by default #82

Merged
merged 3 commits into from
Nov 29, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ See also these two great articles:

If you want to chat, you can find us at Slack! [<img src="https://img.shields.io/badge/gophers-gocron-brightgreen?logo=slack">](https://gophers.slack.com/archives/CQ7T0T1FW)

# Examples:
## Examples:

```go
package main
Expand Down Expand Up @@ -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)

Expand All @@ -89,14 +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)

// Delay start of job
s2.Every(1).Hour().StartAt(time.Now().Add(time.Duration(1 * time.Hour)).Do(task)

// use .StartImmediately() to run job upon scheduler start
s2.Every(1).Hour().StartImmediately().Do(task)


// NextRun gets the next running time
_, time := s2.NextRun()
fmt.Println(time)
Expand Down
8 changes: 1 addition & 7 deletions example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,7 @@ func ExampleScheduler_StartBlocking() {
func ExampleScheduler_StartAsync() {
s := gocron.NewScheduler(time.UTC)
_, _ = s.Every(3).Seconds().Do(task)
<-s.StartAsync()
}

func ExampleScheduler_StartImmediately() {
s := gocron.NewScheduler(time.UTC)
_, _ = s.Every(1).Hour().StartImmediately().Do(task)
s.StartBlocking()
s.StartAsync()
}

func ExampleScheduler_StartAt() {
Expand Down
29 changes: 14 additions & 15 deletions job.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,20 @@ type jobInterval uint64
// Job struct stores the information necessary to run a Job
type Job struct {
sync.RWMutex
interval jobInterval // pause interval * unit between runs
unit timeUnit // time units, ,e.g. 'minutes', 'hours'...
startsImmediately bool // if the Job should run upon scheduler start
jobFunc string // the Job jobFunc to run, func[jobFunc]
atTime time.Duration // optional time at which this Job runs
err error // error related to Job
lastRun time.Time // datetime of last run
nextRun time.Time // datetime of next run
scheduledWeekday *time.Weekday // Specific day of the week to start on
dayOfTheMonth int // Specific day of the month to run the job
funcs map[string]interface{} // Map for the function task store
fparams map[string][]interface{} // Map for function and params of function
tags []string // allow the user to tag Jobs with certain labels
runConfig runConfig // configuration for how many times to run the job
runCount int // number of time the job ran
interval jobInterval // pause interval * unit between runs
unit timeUnit // time units, ,e.g. 'minutes', 'hours'...
jobFunc string // the Job jobFunc to run, func[jobFunc]
atTime time.Duration // optional time at which this Job runs
err error // error related to Job
lastRun time.Time // datetime of last run
nextRun time.Time // datetime of next run
scheduledWeekday *time.Weekday // Specific day of the week to start on
dayOfTheMonth int // Specific day of the month to run the job
funcs map[string]interface{} // Map for the function task store
fparams map[string][]interface{} // Map for function and params of function
tags []string // allow the user to tag Jobs with certain labels
runConfig runConfig // configuration for how many times to run the job
runCount int // number of time the job ran
}

type runConfig struct {
Expand Down
23 changes: 9 additions & 14 deletions scheduler.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.atTime == 0 && job.scheduledWeekday == nil && job.dayOfTheMonth == 0 {
JohnRoesler marked this conversation as resolved.
Show resolved Hide resolved
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)
Expand Down Expand Up @@ -438,13 +440,6 @@ func (s *Scheduler) StartAt(t time.Time) *Scheduler {
return s
}

// StartImmediately sets the Jobs next run as soon as the scheduler starts
func (s *Scheduler) StartImmediately() *Scheduler {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a backward-incompatible change, right?
Is that ok?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we could deprecate the fuction before removing it

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like deprecating. Also, I made some updates. Setting the starts immediately value as true in the constructor and then false where appropriate in At, Start At, Weekday and Day of the Month

job := s.getCurrentJob()
job.startsImmediately = true
return s
}

// shouldRun returns true if the Job should be run now
func (s *Scheduler) shouldRun(j *Job) bool {
return j.shouldRun() && s.time.Now(s.loc).Unix() >= j.nextRun.Unix()
Expand Down
82 changes: 40 additions & 42 deletions scheduler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -95,20 +95,6 @@ func TestScheduledWithTag(t *testing.T) {
}
}

func TestStartImmediately(t *testing.T) {
sched := NewScheduler(time.UTC)
now := time.Now().UTC()

job, _ := sched.Every(1).Hour().StartImmediately().Do(task)
sched.scheduleAllJobs()
next := job.ScheduledTime()

nextRounded := time.Date(next.Year(), next.Month(), next.Day(), next.Hour(), next.Minute(), next.Second(), 0, time.UTC)
expected := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second(), 0, time.UTC)

assert.Exactly(t, expected, nextRounded)
}

func TestAtFuture(t *testing.T) {
s := NewScheduler(time.UTC)
now := time.Now().UTC()
Expand All @@ -135,22 +121,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
}
Expand All @@ -159,23 +173,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)
Expand All @@ -188,7 +186,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)
Expand Down Expand Up @@ -386,7 +384,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) {
Expand Down