-
-
Notifications
You must be signed in to change notification settings - Fork 310
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
issue-740: expand oneTimeJob to support multiple times #741
Merged
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,7 @@ import ( | |
"errors" | ||
"fmt" | ||
"math/rand" | ||
"sort" | ||
"strings" | ||
"time" | ||
|
||
|
@@ -446,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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I had to change the signature of this exported type - I tried to think about situations where this would not be considered a backwards-compatible change but I could not think of one. |
||
|
||
// 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 | ||
} | ||
} | ||
|
||
|
@@ -486,6 +499,18 @@ func OneTimeJob(startAt OneTimeJobStartAtOption) JobDefinition { | |
} | ||
} | ||
|
||
func timeCmp() func(element time.Time, target time.Time) int { | ||
return func(element time.Time, target time.Time) int { | ||
if element.Equal(target) { | ||
return 0 | ||
} | ||
if element.Before(target) { | ||
return -1 | ||
} | ||
return 1 | ||
} | ||
} | ||
|
||
// ----------------------------------------------- | ||
// ----------------------------------------------- | ||
// ----------------- Job Options ----------------- | ||
|
@@ -876,10 +901,33 @@ func (m monthlyJob) nextMonthDayAtTime(lastRun time.Time, days []int, firstPass | |
|
||
var _ jobSchedule = (*oneTimeJob)(nil) | ||
|
||
type oneTimeJob struct{} | ||
type oneTimeJob struct { | ||
sortedTimes []time.Time | ||
} | ||
|
||
func (o oneTimeJob) next(_ time.Time) time.Time { | ||
return time.Time{} | ||
// next finds the next item in a sorted list of times using binary-search. | ||
// | ||
// example: sortedTimes: [2, 4, 6, 8] | ||
// | ||
// lastRun: 1 => [idx=0,found=false] => next is 2 - sorted[idx] idx=0 | ||
// lastRun: 2 => [idx=0,found=true] => next is 4 - sorted[idx+1] idx=1 | ||
// lastRun: 3 => [idx=1,found=false] => next is 4 - sorted[idx] idx=1 | ||
// lastRun: 4 => [idx=1,found=true] => next is 6 - sorted[idx+1] idx=2 | ||
// 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 (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(o.sortedTimes) { | ||
return time.Time{} | ||
} | ||
|
||
return o.sortedTimes[idx] | ||
} | ||
|
||
// ----------------------------------------------- | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've used this in other places, Before vs. Compare. SortStable, which isn't super important here, just keeps the order if items are duplicates