Skip to content

Commit

Permalink
issue-742: followup comments and reuse oneTimeJob
Browse files Browse the repository at this point in the history
  • Loading branch information
rbroggi committed Jun 21, 2024
1 parent 1f81cb6 commit 6c90846
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 70 deletions.
1 change: 0 additions & 1 deletion errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ var (
ErrNewJobWrongNumberOfParameters = fmt.Errorf("gocron: NewJob: Number of provided parameters does not match expected")
ErrNewJobWrongTypeOfParameters = fmt.Errorf("gocron: NewJob: Type of provided parameters does not match expected")
ErrOneTimeJobStartDateTimePast = fmt.Errorf("gocron: OneTimeJob: start must not be in the past")
ErrAtTimesJobAtLeastOneInFuture = fmt.Errorf("gocron: AtTimesJob: at least one point in time must be in the future")
ErrStopExecutorTimedOut = fmt.Errorf("gocron: timed out waiting for executor to stop")
ErrStopJobsTimedOut = fmt.Errorf("gocron: timed out waiting for jobs to finish")
ErrStopSchedulerTimedOut = fmt.Errorf("gocron: timed out waiting for scheduler to stop")
Expand Down
22 changes: 7 additions & 15 deletions example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -354,24 +354,16 @@ func ExampleOneTimeJob() {
func() {},
),
)

s.Start()
}

func ExampleAtTimesJob() {
s, _ := NewScheduler()
defer func() { _ = s.Shutdown() }()

// run job in 10 seconds and in 55 minutes from now
// run job twice - once in 10 seconds and once in 55 minutes
n := time.Now()
_, _ = s.NewJob(
AtTimesJob(
n.Add(10*time.Second),
n.Add(55*time.Minute),
),
NewTask(
func() {},
OneTimeJob(
OneTimeJobStartDateTimes(
n.Add(10*time.Second),
n.Add(55*time.Minute),
),
),
NewTask(func() {}),
)

s.Start()
Expand Down
80 changes: 29 additions & 51 deletions job.go
Original file line number Diff line number Diff line change
Expand Up @@ -447,35 +447,47 @@ type oneTimeJobDefinition struct {
}

func (o oneTimeJobDefinition) setup(j *internalJob, _ *time.Location, now time.Time) error {
j.jobSchedule = oneTimeJob{}
if err := o.startAt(j); err != nil {
return err
sortedTimes := o.startAt(j)
sort.Slice(sortedTimes, func(i, j int) bool {
return sortedTimes[i].Before(sortedTimes[j])
})
// keep only schedules that are in the future
idx, found := slices.BinarySearchFunc(sortedTimes, now, timeCmp())
if found {
idx++
}
// in case we are not in the `startImmediately` case, our start-date must be in
// the future according to the scheduler clock
if !j.startImmediately && (j.startTime.IsZero() || j.startTime.Before(now)) {
sortedTimes = sortedTimes[idx:]
if !j.startImmediately && len(sortedTimes) == 0 {
return ErrOneTimeJobStartDateTimePast
}
j.jobSchedule = oneTimeJob{sortedTimes: sortedTimes}
return nil
}

// OneTimeJobStartAtOption defines when the one time job is run
type OneTimeJobStartAtOption func(*internalJob) error
type OneTimeJobStartAtOption func(*internalJob) []time.Time

// OneTimeJobStartImmediately tells the scheduler to run the one time job immediately.
func OneTimeJobStartImmediately() OneTimeJobStartAtOption {
return func(j *internalJob) error {
return func(j *internalJob) []time.Time {
j.startImmediately = true
return nil
return []time.Time{}
}
}

// OneTimeJobStartDateTime sets the date & time at which the job should run.
// This datetime must be in the future (according to the scheduler clock).
func OneTimeJobStartDateTime(start time.Time) OneTimeJobStartAtOption {
return func(j *internalJob) error {
j.startTime = start
return nil
return func(j *internalJob) []time.Time {
return []time.Time{start}
}
}

// OneTimeJobStartDateTimes sets the date & times at which the job should run.
// At least one of the date/times must be in the future (according to the scheduler clock).
func OneTimeJobStartDateTimes(times ...time.Time) OneTimeJobStartAtOption {
return func(j *internalJob) []time.Time {
return times
}
}

Expand All @@ -487,30 +499,6 @@ func OneTimeJob(startAt OneTimeJobStartAtOption) JobDefinition {
}
}

var _JobDefinition = (*atTimesJobDefinition)(nil)

type atTimesJobDefinition struct {
atTimes []time.Time
}

func (a atTimesJobDefinition) setup(j *internalJob, _ *time.Location, now time.Time) error {
sortedTimes := a.atTimes
sort.Slice(a.atTimes, func(i, j int) bool {
return a.atTimes[i].Before(a.atTimes[j])
})
// keep only schedules that are in the future
idx, found := slices.BinarySearchFunc(sortedTimes, now, timeCmp())
if found {
idx++
}
sortedTimes = sortedTimes[idx:]
if len(sortedTimes) == 0 {
return ErrAtTimesJobAtLeastOneInFuture
}
j.jobSchedule = atTimesJob{sortedTimes: sortedTimes}
return nil
}

func timeCmp() func(element time.Time, target time.Time) int {
return func(element time.Time, target time.Time) int {
if element.Equal(target) {
Expand All @@ -523,10 +511,6 @@ func timeCmp() func(element time.Time, target time.Time) int {
}
}

func AtTimesJob(atTimes ...time.Time) JobDefinition {
return atTimesJobDefinition{atTimes: atTimes}
}

// -----------------------------------------------
// -----------------------------------------------
// ----------------- Job Options -----------------
Expand Down Expand Up @@ -917,13 +901,7 @@ func (m monthlyJob) nextMonthDayAtTime(lastRun time.Time, days []int, firstPass

var _ jobSchedule = (*oneTimeJob)(nil)

type oneTimeJob struct{}

func (o oneTimeJob) next(_ time.Time) time.Time {
return time.Time{}
}

type atTimesJob struct {
type oneTimeJob struct {
sortedTimes []time.Time
}

Expand All @@ -938,18 +916,18 @@ type atTimesJob struct {
// lastRun: 7 => [idx=3,found=false] => next is 8 - sorted[idx] idx=3
// lastRun: 8 => [idx=3,found=found] => next is none
// lastRun: 9 => [idx=3,found=found] => next is none
func (a atTimesJob) next(lastRun time.Time) time.Time {
idx, found := slices.BinarySearchFunc(a.sortedTimes, lastRun, timeCmp())
func (o oneTimeJob) next(lastRun time.Time) time.Time {
idx, found := slices.BinarySearchFunc(o.sortedTimes, lastRun, timeCmp())
// if found, the next run is the following index
if found {
idx++
}
// exhausted runs
if idx >= len(a.sortedTimes) {
if idx >= len(o.sortedTimes) {
return time.Time{}
}

return a.sortedTimes[idx]
return o.sortedTimes[idx]
}

// -----------------------------------------------
Expand Down
6 changes: 3 additions & 3 deletions scheduler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2112,15 +2112,15 @@ func TestScheduler_AtTimesJob(t *testing.T) {
atTimes: []time.Time{},
fakeClock: clockwork.NewFakeClock(),
assertErr: func(t require.TestingT, err error, i ...interface{}) {
require.ErrorIs(t, err, ErrAtTimesJobAtLeastOneInFuture)
require.ErrorIs(t, err, ErrOneTimeJobStartDateTimePast)
},
},
{
name: "all in the past",
atTimes: []time.Time{n.Add(-1 * time.Second)},
fakeClock: clockwork.NewFakeClockAt(n),
assertErr: func(t require.TestingT, err error, i ...interface{}) {
require.ErrorIs(t, err, ErrAtTimesJobAtLeastOneInFuture)
require.ErrorIs(t, err, ErrOneTimeJobStartDateTimePast)
},
},
{
Expand Down Expand Up @@ -2252,7 +2252,7 @@ func TestScheduler_AtTimesJob(t *testing.T) {

runs := atomic.Uint32{}
j, err := s.NewJob(
AtTimesJob(tt.atTimes...),
OneTimeJob(OneTimeJobStartDateTimes(tt.atTimes...)),
NewTask(func() {
runs.Add(1)
}),
Expand Down

0 comments on commit 6c90846

Please sign in to comment.