Skip to content
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

cron/byTime: Optimization determine the nexe entry #409

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 15 additions & 7 deletions cron.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package cron

import (
"context"
"sort"
"sync"
"time"
)
Expand Down Expand Up @@ -74,12 +73,10 @@ type Entry struct {
// Valid returns true if this is not the zero entry.
func (e Entry) Valid() bool { return e.ID != 0 }

// byTime is a wrapper for sorting the entry array by time
// byTime is a wrapper for get the minimum entry index from the array by time
// (with zero time at the end).
type byTime []*Entry

func (s byTime) Len() int { return len(s) }
func (s byTime) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s byTime) Less(i, j int) bool {
// Two zero times should return false.
// Otherwise, zero is "greater" than any other time.
Expand All @@ -93,6 +90,17 @@ func (s byTime) Less(i, j int) bool {
return s[i].Next.Before(s[j].Next)
}

// Get the minimum entry index from the array by time
func (s byTime) Min() int {
min := 0
for i := range s {
if s.Less(i, min) {
min = i
}
}
return min
}

// New returns a new Cron job runner, modified by the given options.
//
// Available Settings
Expand Down Expand Up @@ -248,15 +256,15 @@ func (c *Cron) run() {

for {
// Determine the next entry to run.
sort.Sort(byTime(c.entries))
min := byTime(c.entries).Min()

var timer *time.Timer
if len(c.entries) == 0 || c.entries[0].Next.IsZero() {
if len(c.entries) == 0 || c.entries[min].Next.IsZero() {
// If there are no entries yet, just sleep - it still handles new entries
// and stop requests.
timer = time.NewTimer(100000 * time.Hour)
} else {
timer = time.NewTimer(c.entries[0].Next.Sub(now))
timer = time.NewTimer(c.entries[min].Next.Sub(now))
}

for {
Expand Down
24 changes: 24 additions & 0 deletions cron_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -678,6 +678,30 @@ func TestMultiThreadedStartAndStop(t *testing.T) {
cron.Stop()
}

func TestMinimumTime(t *testing.T) {
now := time.Now()
times := []time.Time{
now.Add(time.Second * 3),
now.Add(time.Second * 2),
now.Add(time.Second * -1),
now.Add(time.Minute * 1),
now.Add(time.Minute * -3),
now.Add(time.Minute * -2),
now.Add(time.Second * -180),
now.Add(time.Second * 2),
}
expected := 4

entries := []*Entry{}
for _, t := range times {
entries = append(entries, &Entry{Next: t})
}

if byTime(entries).Min() != expected {
t.Error("Get the minimum entry index by time is unexpected")
}
}

func wait(wg *sync.WaitGroup) chan bool {
ch := make(chan bool)
go func() {
Expand Down