Skip to content

Commit

Permalink
backport of commit 3b9283a (#23330)
Browse files Browse the repository at this point in the history
Co-authored-by: Daniel Bennett <[email protected]>
  • Loading branch information
hc-github-team-nomad-core and gulducat authored Jun 14, 2024
1 parent 5aeec72 commit ec7049c
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 5 deletions.
3 changes: 3 additions & 0 deletions .changelog/23329.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:bug
task schedule: Fixed a bug where schedules wrongly errored as invalid on the last day of the month
```
10 changes: 5 additions & 5 deletions nomad/structs/task_sched.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,11 +141,6 @@ func (t TaskScheduleCron) Next(from time.Time) (time.Duration, time.Duration, er
return 0, 0, fmt.Errorf("invalid end time in schedule: %q; %w", t.End, err)
}

// next end must be later than next start on the same day
if end.Next(from).Day() > start.Next(from).Day() {
return 0, 0, fmt.Errorf("end cannot be sooner than start")
}

startNext := start.Next(from)
// we'll check the previous start to see if we are currently between it
// and the previous run's end, i.e. it should be running right now!
Expand All @@ -155,6 +150,11 @@ func (t TaskScheduleCron) Next(from time.Time) (time.Duration, time.Duration, er
endNext := end.Next(startNext)
endPrev := end.Next(startPrev)

// next end must be on the same day as next start
if endNext.Day() > startNext.Day() {
return 0, 0, fmt.Errorf("end cannot be sooner than start; end=%q, start=%q", endNext, startNext)
}

// we're in the midst of it right now!
if startPrev.Before(from) && endPrev.After(from) {
return 0, endPrev.Sub(from), nil
Expand Down
36 changes: 36 additions & 0 deletions nomad/structs/task_sched_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,34 @@ import (
"github.com/shoenig/test/must"
)

func FuzzTaskScheduleCron(f *testing.F) {
// valid values to compare against varying "now"s
sched := TaskScheduleCron{
Start: "0 11 * * * *",
End: "0 13",
Timezone: "UTC", // this timezone must match the fake "now" in Fuzz()
}

// seed the corpus with some target "now"s to time-travel to
// args: year, month, day, hour, minute
f.Add(0, 0, 0, 0, 0) // zero
f.Add(1970, 1, 0, 0, 0) // epoch start
f.Add(2000, 1, 0, 0, 0) // y2k
f.Add(2024, 12, 31, 23, 59) // end of this year
f.Add(2038, 1, 19, 3, 0) // y2kv2

// regression tests:
// schedule should be valid on the last day of the month.
f.Add(2024, 6, 30, 12, 0)

f.Fuzz(func(t *testing.T, year, month, day, hour, minute int) {
now := time.Date(year, time.Month(month), day, hour, minute, 0, 0, time.UTC)
_, _, err := sched.Next(now)
must.NoError(t, err,
must.Sprintf("from=%q start=%q end=%q", now, sched.Start, sched.End))
})
}

func TestTaskScheduleCron(t *testing.T) {
ci.Parallel(t)

Expand Down Expand Up @@ -113,6 +141,14 @@ func TestTaskScheduleCron(t *testing.T) {
expectNext: 23*time.Hour + 30*time.Minute, // monday morning
expectEnd: (24 + 6) * time.Hour, // monday afternoon
},
{
name: "end of the month", // regression test for false "end cannot be sooner than start"
now: "2024-06-30T10:00:00Z", // june has 30 days
start: "0 9 * * * *", // start before now
end: "0 11", // end after now
expectNext: 0, // should be running
expectEnd: time.Hour,
},
// errors
{
name: "bad tz",
Expand Down

0 comments on commit ec7049c

Please sign in to comment.