Skip to content

Commit

Permalink
origin modules not active,thanks robfig#317
Browse files Browse the repository at this point in the history
  • Loading branch information
penglj committed May 9, 2022
1 parent 457b79b commit e4edd23
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 8 deletions.
4 changes: 4 additions & 0 deletions constantdelay.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ func (schedule ConstantDelaySchedule) Next(t time.Time) time.Time {
return t.Add(schedule.Delay - time.Duration(t.Nanosecond())*time.Nanosecond)
}

func (schedule ConstantDelaySchedule) IsOnce() bool {
return false
}

// Prev returns the previous time this should be run.
// This rounds so that the previous activation time will be on the second.
func (schedule ConstantDelaySchedule) Prev(t time.Time) time.Time {
Expand Down
13 changes: 12 additions & 1 deletion cron.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ type Schedule interface {

// Prev returns the previous activation time, earlier than the given time.
Prev(time.Time) time.Time
IsOnce() bool
}

// EntryID identifies an entry within a Cron instance
Expand Down Expand Up @@ -319,16 +320,26 @@ func (c *Cron) run() {
now = now.In(c.location)
c.logger.Info("wake", "now", now)

del := 0

// Run every entry whose next time was less than now
for _, e := range c.entries {
for k, e := range c.entries {
if e.Next.After(now) || e.Next.IsZero() {
break
}

c.startJob(e.WrappedJob)
e.Prev = e.Next
e.Next = e.Schedule.Next(now)
c.logger.Info("run", "now", now, "entry", e.ID, "next", e.Next)
// only run once
if e.Schedule.IsOnce() {
c.entries[k] = c.entries[del]
del++
}

}
c.entries = c.entries[del:]

case newEntry := <-c.add:
timer.Stop()
Expand Down
4 changes: 4 additions & 0 deletions cron_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,10 @@ func (*ZeroSchedule) Prev(time.Time) time.Time {
return time.Time{}
}

func (*ZeroSchedule) IsOnce() bool {
return false
}

// Tests that job without time does not run
func TestJobWithZeroTimeDoesNotRun(t *testing.T) {
cron := newWithSeconds()
Expand Down
1 change: 1 addition & 0 deletions doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ them in their own goroutines.
c.AddFunc("CRON_TZ=Asia/Tokyo 30 04 * * *", func() { fmt.Println("Runs at 04:30 Tokyo time every day") })
c.AddFunc("@hourly", func() { fmt.Println("Every hour, starting an hour from now") })
c.AddFunc("@every 1h30m", func() { fmt.Println("Every hour thirty, starting an hour thirty from now") })
c.AddFunc("@once 2020-06-02 17:04:31", func() { fmt.Println("Hello! Now is 2020-06-02 17:04:31") })
c.Start()
..
// Funcs are invoked in their own goroutine, asynchronously.
Expand Down
31 changes: 30 additions & 1 deletion parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,6 @@ func mustParseInt(expr string) (uint, error) {
// getBits sets all bits in the range [min, max], modulo the given step size.
func getBits(min, max, step uint) uint64 {
var bits uint64

// If step is 1, use shifts.
if step == 1 {
return ^(math.MaxUint64 << (max + 1)) & (math.MaxUint64 << min)
Expand Down Expand Up @@ -445,5 +444,35 @@ func parseDescriptor(descriptor string, loc *time.Location) (Schedule, error) {
return Every(duration), nil
}

const once = "@once "
if strings.HasPrefix(descriptor, once) {
runDate, err := time.Parse("2006-01-02 15:04:05", strings.Replace(descriptor, once, "", 1))
if err != nil {
return nil, fmt.Errorf("failed to parse duration %s: %s", descriptor, err)
}

var (
second = uint(runDate.Second())
minute = uint(runDate.Minute())
hour = uint(runDate.Hour())
dom = uint(runDate.Day())
month = uint(runDate.Month())
year = uint(runDate.Year())
)

ret := &SpecSchedule{
Second: uint64(second),
Minute: uint64(minute),
Hour: uint64(hour),
Dom: uint64(dom),
Month: uint64(month),
Year: uint64(year),
Dow: all(dow),
Once: true,
Location: loc,
}
return ret, nil
}

return nil, fmt.Errorf("unrecognized descriptor: %s", descriptor)
}
8 changes: 4 additions & 4 deletions parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ func TestStandardSpecSchedule(t *testing.T) {
}{
{
expr: "5 * * * *",
expected: &SpecSchedule{1 << seconds.min, 1 << 5, all(hours), all(dom), all(months), all(dow), time.Local},
expected: &SpecSchedule{1 << seconds.min, 1 << 5, all(hours), all(dom), all(months), all(dow), 0, false, time.Local},
},
{
expr: "@every 5m",
Expand Down Expand Up @@ -359,15 +359,15 @@ func TestNoDescriptorParser(t *testing.T) {
}

func every5min(loc *time.Location) *SpecSchedule {
return &SpecSchedule{1 << 0, 1 << 5, all(hours), all(dom), all(months), all(dow), loc}
return &SpecSchedule{1 << 0, 1 << 5, all(hours), all(dom), all(months), all(dow), 0, false, loc}
}

func every5min5s(loc *time.Location) *SpecSchedule {
return &SpecSchedule{1 << 5, 1 << 5, all(hours), all(dom), all(months), all(dow), loc}
return &SpecSchedule{1 << 5, 1 << 5, all(hours), all(dom), all(months), all(dow), 0, false, loc}
}

func midnight(loc *time.Location) *SpecSchedule {
return &SpecSchedule{1, 1, 1, all(dom), all(months), all(dow), loc}
return &SpecSchedule{1, 1, 1, all(dom), all(months), all(dow), 0, false, loc}
}

func annual(loc *time.Location) *SpecSchedule {
Expand Down
13 changes: 11 additions & 2 deletions spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import (
// SpecSchedule specifies a duty cycle (to the second granularity), based on a
// traditional crontab specification. It is computed initially and stored as bit sets.
type SpecSchedule struct {
Second, Minute, Hour, Dom, Month, Dow uint64

Second, Minute, Hour, Dom, Month, Dow, Year uint64
Once bool
// Override location for this schedule.
Location *time.Location
}
Expand Down Expand Up @@ -78,9 +78,18 @@ const (
starBit = 1 << 63
)

func (s *SpecSchedule) IsOnce() bool {
return s.Once
}

// Next returns the next time this schedule is activated, greater than the given
// time. If no time can be found to satisfy the schedule, return the zero time.
func (s *SpecSchedule) Next(t time.Time) time.Time {
// Once Task is definite datetime
if s.Once {
return time.Date(int(s.Year), time.Month(s.Month), int(s.Dom), int(s.Hour), int(s.Minute), int(s.Second), 0, s.Location)
}

// General approach
//
// For Month, Day, Hour, Minute, Second:
Expand Down

0 comments on commit e4edd23

Please sign in to comment.