Skip to content

Commit a4b6a7b

Browse files
author
penglj
committed
origin modules not active,thanks robfig#446
1 parent e4edd23 commit a4b6a7b

File tree

2 files changed

+47
-7
lines changed

2 files changed

+47
-7
lines changed

cron.go

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,17 @@ type Entry struct {
8888
// Valid returns true if this is not the zero entry.
8989
func (e Entry) Valid() bool { return e.ID != 0 }
9090

91+
// ScheduleFirst is used for the initial scheduling. If a Prev value has been
92+
// included with the Entry, it will be used in place of "now" to allow schedules
93+
// to be preserved across process restarts.
94+
func (e Entry) ScheduleFirst(now time.Time) time.Time {
95+
if !e.Prev.IsZero() {
96+
return e.Schedule.Next(e.Prev)
97+
} else {
98+
return e.Schedule.Next(now)
99+
}
100+
}
101+
91102
// byTime is a wrapper for sorting the entry array by time
92103
// (with zero time at the end).
93104
type byTime []*Entry
@@ -154,25 +165,25 @@ func (f FuncJob) Run() { f() }
154165
// AddFunc adds a func to the Cron to be run on the given schedule.
155166
// The spec is parsed using the time zone of this Cron instance as the default.
156167
// An opaque ID is returned that can be used to later remove it.
157-
func (c *Cron) AddFunc(spec string, cmd func()) (EntryID, error) {
158-
return c.AddJob(spec, FuncJob(cmd))
168+
func (c *Cron) AddFunc(spec string, cmd func(), entryOpts ...EntryOption) (EntryID, error) {
169+
return c.AddJob(spec, FuncJob(cmd), entryOpts...)
159170
}
160171

161172
// AddJob adds a Job to the Cron to be run on the given schedule.
162173
// The spec is parsed using the time zone of this Cron instance as the default.
163174
// An opaque ID is returned that can be used to later remove it.
164-
func (c *Cron) AddJob(spec string, cmd Job) (EntryID, error) {
175+
func (c *Cron) AddJob(spec string, cmd Job, entryOpts ...EntryOption) (EntryID, error) {
165176
schedule, err := c.parser.Parse(spec)
166177

167178
if err != nil {
168179
return 0, err
169180
}
170-
return c.Schedule(schedule, cmd), nil
181+
return c.Schedule(schedule, cmd, entryOpts...), nil
171182
}
172183

173184
// Schedule adds a Job to the Cron to be run on the given schedule.
174185
// The job is wrapped with the configured Chain.
175-
func (c *Cron) Schedule(schedule Schedule, cmd Job) EntryID {
186+
func (c *Cron) Schedule(schedule Schedule, cmd Job, entryOpts ...EntryOption) EntryID {
176187
c.runningMu.Lock()
177188
defer c.runningMu.Unlock()
178189
c.nextID++
@@ -182,6 +193,9 @@ func (c *Cron) Schedule(schedule Schedule, cmd Job) EntryID {
182193
WrappedJob: c.chain.Then(cmd),
183194
Job: cmd,
184195
}
196+
for _, fn := range entryOpts {
197+
fn(entry)
198+
}
185199
if !c.running {
186200
c.entries = append(c.entries, entry)
187201
} else {
@@ -223,6 +237,18 @@ func (c *Cron) UpdateSchedule(id EntryID, schedule Schedule) error {
223237
return errors.New(fmt.Sprintf("invalid ID provided: %d", id))
224238
}
225239

240+
// EntryOption is a hook which allows the Entry to be altered before being
241+
// committed internally.
242+
type EntryOption func(*Entry)
243+
244+
// EntryPrev allows setting the Prev time to allow interval-based schedules to
245+
// preserve their timeline even in the face of process restarts.
246+
func WithPrev(prev time.Time) EntryOption {
247+
return func(e *Entry) {
248+
e.Prev = prev
249+
}
250+
}
251+
226252
// Entries returns a snapshot of the cron entries.
227253
func (c *Cron) Entries() []Entry {
228254
c.runningMu.Lock()
@@ -306,7 +332,7 @@ func (c *Cron) run() {
306332
// Figure out the next activation times for each entry.
307333
now := c.now()
308334
for _, entry := range c.entries {
309-
entry.Next = entry.Schedule.Next(now)
335+
entry.Next = entry.ScheduleFirst(now)
310336
c.logger.Info("schedule", "now", now, "entry", entry.ID, "next", entry.Next)
311337
}
312338

@@ -344,7 +370,7 @@ func (c *Cron) run() {
344370
case newEntry := <-c.add:
345371
timer.Stop()
346372
now = c.now()
347-
newEntry.Next = newEntry.Schedule.Next(now)
373+
newEntry.Next = newEntry.ScheduleFirst(now)
348374
c.entries = append(c.entries, newEntry)
349375
c.logger.Info("added", "now", now, "entry", newEntry.ID, "next", newEntry.Next)
350376

cron_test.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -679,6 +679,20 @@ func TestStopAndWait(t *testing.T) {
679679
})
680680
}
681681

682+
func TestJobWithCustomPrev(t *testing.T) {
683+
cron := New()
684+
var calls int64
685+
// running every 3s, but starting 2s in the past
686+
// expected timeline: 1s ... 4s ... stop (2 calls)
687+
// if prev was ignored, the func would only be called once (at 3s)
688+
cron.AddFunc("@every 3s", func() { atomic.AddInt64(&calls, 1) }, WithPrev(time.Now().Add(-2*time.Second)))
689+
cron.Start()
690+
time.Sleep(5 * time.Second)
691+
if atomic.LoadInt64(&calls) != 2 {
692+
t.Errorf("called %d times, expected 2\n", calls)
693+
}
694+
}
695+
682696
func TestMultiThreadedStartAndStop(t *testing.T) {
683697
cron := New()
684698
go cron.Run()

0 commit comments

Comments
 (0)