@@ -74,6 +74,17 @@ type Entry struct {
74
74
// Valid returns true if this is not the zero entry.
75
75
func (e Entry ) Valid () bool { return e .ID != 0 }
76
76
77
+ // ScheduleFirst is used for the initial scheduling. If a Prev value has been
78
+ // included with the Entry, it will be used in place of "now" to allow schedules
79
+ // to be preserved across process restarts.
80
+ func (e Entry ) ScheduleFirst (now time.Time ) time.Time {
81
+ if ! e .Prev .IsZero () {
82
+ return e .Schedule .Next (e .Prev )
83
+ } else {
84
+ return e .Schedule .Next (now )
85
+ }
86
+ }
87
+
77
88
// byTime is a wrapper for sorting the entry array by time
78
89
// (with zero time at the end).
79
90
type byTime []* Entry
@@ -138,24 +149,24 @@ func (f FuncJob) Run() { f() }
138
149
// AddFunc adds a func to the Cron to be run on the given schedule.
139
150
// The spec is parsed using the time zone of this Cron instance as the default.
140
151
// An opaque ID is returned that can be used to later remove it.
141
- func (c * Cron ) AddFunc (spec string , cmd func ()) (EntryID , error ) {
142
- return c .AddJob (spec , FuncJob (cmd ))
152
+ func (c * Cron ) AddFunc (spec string , cmd func (), entryOpts ... EntryOption ) (EntryID , error ) {
153
+ return c .AddJob (spec , FuncJob (cmd ), entryOpts ... )
143
154
}
144
155
145
156
// AddJob adds a Job to the Cron to be run on the given schedule.
146
157
// The spec is parsed using the time zone of this Cron instance as the default.
147
158
// An opaque ID is returned that can be used to later remove it.
148
- func (c * Cron ) AddJob (spec string , cmd Job ) (EntryID , error ) {
159
+ func (c * Cron ) AddJob (spec string , cmd Job , entryOpts ... EntryOption ) (EntryID , error ) {
149
160
schedule , err := c .parser .Parse (spec )
150
161
if err != nil {
151
162
return 0 , err
152
163
}
153
- return c .Schedule (schedule , cmd ), nil
164
+ return c .Schedule (schedule , cmd , entryOpts ... ), nil
154
165
}
155
166
156
167
// Schedule adds a Job to the Cron to be run on the given schedule.
157
168
// The job is wrapped with the configured Chain.
158
- func (c * Cron ) Schedule (schedule Schedule , cmd Job ) EntryID {
169
+ func (c * Cron ) Schedule (schedule Schedule , cmd Job , entryOpts ... EntryOption ) EntryID {
159
170
c .runningMu .Lock ()
160
171
defer c .runningMu .Unlock ()
161
172
c .nextID ++
@@ -165,6 +176,9 @@ func (c *Cron) Schedule(schedule Schedule, cmd Job) EntryID {
165
176
WrappedJob : c .chain .Then (cmd ),
166
177
Job : cmd ,
167
178
}
179
+ for _ , fn := range entryOpts {
180
+ fn (entry )
181
+ }
168
182
if ! c .running {
169
183
heap .Push (& c .entries , entry )
170
184
} else {
@@ -173,6 +187,18 @@ func (c *Cron) Schedule(schedule Schedule, cmd Job) EntryID {
173
187
return entry .ID
174
188
}
175
189
190
+ // EntryOption is a hook which allows the Entry to be altered before being
191
+ // committed internally.
192
+ type EntryOption func (* Entry )
193
+
194
+ // WithPrev allows setting the Prev time to allow interval-based schedules to
195
+ // preserve their timeline even in the face of process restarts.
196
+ func WithPrev (prev time.Time ) EntryOption {
197
+ return func (e * Entry ) {
198
+ e .Prev = prev
199
+ }
200
+ }
201
+
176
202
// Entries returns a snapshot of the cron entries.
177
203
func (c * Cron ) Entries () []Entry {
178
204
c .runningMu .Lock ()
@@ -244,7 +270,7 @@ func (c *Cron) run() {
244
270
sortedEntries := new (EntryHeap )
245
271
for len (c .entries ) > 0 {
246
272
entry := heap .Pop (& c .entries ).(* Entry )
247
- entry .Next = entry .Schedule . Next (now )
273
+ entry .Next = entry .ScheduleFirst (now )
248
274
heap .Push (sortedEntries , entry )
249
275
c .logger .Info ("schedule" , "now" , now , "entry" , entry .ID , "next" , entry .Next )
250
276
}
@@ -287,7 +313,7 @@ func (c *Cron) run() {
287
313
case newEntry := <- c .add :
288
314
timer .Stop ()
289
315
now = c .now ()
290
- newEntry .Next = newEntry .Schedule . Next (now )
316
+ newEntry .Next = newEntry .ScheduleFirst (now )
291
317
heap .Push (& c .entries , newEntry )
292
318
c .logger .Info ("added" , "now" , now , "entry" , newEntry .ID , "next" , newEntry .Next )
293
319
0 commit comments