@@ -88,6 +88,17 @@ type Entry struct {
88
88
// Valid returns true if this is not the zero entry.
89
89
func (e Entry ) Valid () bool { return e .ID != 0 }
90
90
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
+
91
102
// byTime is a wrapper for sorting the entry array by time
92
103
// (with zero time at the end).
93
104
type byTime []* Entry
@@ -154,25 +165,25 @@ func (f FuncJob) Run() { f() }
154
165
// AddFunc adds a func to the Cron to be run on the given schedule.
155
166
// The spec is parsed using the time zone of this Cron instance as the default.
156
167
// 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 ... )
159
170
}
160
171
161
172
// AddJob adds a Job to the Cron to be run on the given schedule.
162
173
// The spec is parsed using the time zone of this Cron instance as the default.
163
174
// 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 ) {
165
176
schedule , err := c .parser .Parse (spec )
166
177
167
178
if err != nil {
168
179
return 0 , err
169
180
}
170
- return c .Schedule (schedule , cmd ), nil
181
+ return c .Schedule (schedule , cmd , entryOpts ... ), nil
171
182
}
172
183
173
184
// Schedule adds a Job to the Cron to be run on the given schedule.
174
185
// 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 {
176
187
c .runningMu .Lock ()
177
188
defer c .runningMu .Unlock ()
178
189
c .nextID ++
@@ -182,6 +193,9 @@ func (c *Cron) Schedule(schedule Schedule, cmd Job) EntryID {
182
193
WrappedJob : c .chain .Then (cmd ),
183
194
Job : cmd ,
184
195
}
196
+ for _ , fn := range entryOpts {
197
+ fn (entry )
198
+ }
185
199
if ! c .running {
186
200
c .entries = append (c .entries , entry )
187
201
} else {
@@ -223,6 +237,18 @@ func (c *Cron) UpdateSchedule(id EntryID, schedule Schedule) error {
223
237
return errors .New (fmt .Sprintf ("invalid ID provided: %d" , id ))
224
238
}
225
239
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
+
226
252
// Entries returns a snapshot of the cron entries.
227
253
func (c * Cron ) Entries () []Entry {
228
254
c .runningMu .Lock ()
@@ -306,7 +332,7 @@ func (c *Cron) run() {
306
332
// Figure out the next activation times for each entry.
307
333
now := c .now ()
308
334
for _ , entry := range c .entries {
309
- entry .Next = entry .Schedule . Next (now )
335
+ entry .Next = entry .ScheduleFirst (now )
310
336
c .logger .Info ("schedule" , "now" , now , "entry" , entry .ID , "next" , entry .Next )
311
337
}
312
338
@@ -344,7 +370,7 @@ func (c *Cron) run() {
344
370
case newEntry := <- c .add :
345
371
timer .Stop ()
346
372
now = c .now ()
347
- newEntry .Next = newEntry .Schedule . Next (now )
373
+ newEntry .Next = newEntry .ScheduleFirst (now )
348
374
c .entries = append (c .entries , newEntry )
349
375
c .logger .Info ("added" , "now" , now , "entry" , newEntry .ID , "next" , newEntry .Next )
350
376
0 commit comments