Skip to content

Commit

Permalink
fix: return error on NextFireTime for expired cron expression (#70)
Browse files Browse the repository at this point in the history
  • Loading branch information
reugn authored Oct 6, 2023
1 parent 1fb8849 commit cdb58bc
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 10 deletions.
24 changes: 14 additions & 10 deletions quartz/cron.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package quartz

import (
"errors"
"fmt"
"sort"
"strconv"
Expand Down Expand Up @@ -153,13 +154,13 @@ func validateCronExpression(expression string) ([]*cronField, error) {
}
length := len(tokens)
if length < 6 || length > 7 {
return nil, cronError("Invalid expression length")
return nil, cronError("invalid expression length")
}
if length == 6 {
tokens = append(tokens, "*")
}
if (tokens[3] != "?" && tokens[3] != "*") && (tokens[5] != "?" && tokens[5] != "*") {
return nil, cronError("Day field was set twice")
return nil, cronError("day field was set twice")
}

return buildCronField(tokens)
Expand Down Expand Up @@ -224,7 +225,7 @@ func parseField(field string, min int, max int, translate ...[]string) (*cronFie
if inScope(i, min, max) {
return &cronField{[]int{i}}, nil
}
return nil, cronError("Single min/max validation error")
return nil, cronError("single min/max validation error")
}

// list values
Expand All @@ -249,11 +250,11 @@ func parseField(field string, min int, max int, translate ...[]string) (*cronFie
if inScope(i, min, max) {
return &cronField{[]int{i}}, nil
}
return nil, cronError("Cron literal min/max validation error")
return nil, cronError("cron literal min/max validation error")
}
}

return nil, cronError("Cron parse error")
return nil, cronError("cron parse error")
}

func parseListField(field string, translate []string) (*cronField, error) {
Expand All @@ -274,13 +275,13 @@ func parseRangeField(field string, min int, max int, translate []string) (*cronF
var _range []int
t := strings.Split(field, "-")
if len(t) != 2 {
return nil, cronError("Parse cron range error")
return nil, cronError("parse cron range error")
}

from := normalize(t[0], translate)
to := normalize(t[1], translate)
if !inScope(from, min, max) || !inScope(to, min, max) {
return nil, cronError("Cron range min/max validation error")
return nil, cronError("cron range min/max validation error")
}

_range, err := fillRange(from, to)
Expand All @@ -295,7 +296,7 @@ func parseStepField(field string, min int, max int, translate []string) (*cronFi
var _step []int
t := strings.Split(field, "/")
if len(t) != 2 {
return nil, cronError("Parse cron step error")
return nil, cronError("parse cron step error")
}

if t[0] == "*" {
Expand All @@ -305,7 +306,7 @@ func parseStepField(field string, min int, max int, translate []string) (*cronFi
from := normalize(t[0], translate)
step := atoi(t[1])
if !inScope(from, min, max) {
return nil, cronError("Cron step min/max validation error")
return nil, cronError("cron step min/max validation error")
}

_step, err := fillStep(from, step, max)
Expand All @@ -316,9 +317,12 @@ func parseStepField(field string, min int, max int, translate []string) (*cronFi
return &cronField{_step}, nil
}

func (parser *cronExpressionParser) nextTime(prev time.Time, fields []*cronField) (nextTime int64, err error) {
func (parser *cronExpressionParser) nextTime(prev time.Time, fields []*cronField) (int64, error) {
// Build CronStateMachine and run once
csm := makeCSMFromFields(prev, fields)
nextDateTime := csm.NextTriggerTime(prev.Location())
if nextDateTime.Before(prev) || nextDateTime.Equal(prev) {
return 0, errors.New("next trigger time is in the past")
}
return nextDateTime.UnixNano(), nil
}
13 changes: 13 additions & 0 deletions quartz/cron_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,19 @@ func TestCronExpression14(t *testing.T) {
assertEqual(t, result, "Wed May 1 00:00:00 2041")
}

func TestCronExpressionExpired(t *testing.T) {
prev := time.Date(2023, 4, 22, 12, 00, 00, 00, time.UTC).UnixNano()
fmt.Println(time.Unix(0, prev).UTC())
cronTrigger, err := quartz.NewCronTrigger("0 0 0 1 1 ? 2023")
if err != nil {
t.Fatal(err)
}
_, err = cronTrigger.NextFireTime(prev)
if err == nil {
t.Fatal("cron expression should be expired")
}
}

func TestCronExpressionWithLoc(t *testing.T) {
loc, err := time.LoadLocation("America/New_York")
prev := time.Date(2023, 4, 29, 12, 00, 00, 00, loc).UnixNano()
Expand Down
2 changes: 2 additions & 0 deletions quartz/scheduler.go
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,8 @@ func (sched *StdScheduler) executeAndReschedule(ctx context.Context) {
it.Job.Execute(ctx)
}()
}
} else {
logger.Debugf("Job %d skipped as outdated %d.", it.Job.Key(), it.priority)
}

// reschedule the Job
Expand Down

0 comments on commit cdb58bc

Please sign in to comment.