@@ -24,6 +24,7 @@ type internalJob struct {
24
24
id uuid.UUID
25
25
name string
26
26
tags []string
27
+ cron Cron
27
28
jobSchedule
28
29
29
30
// as some jobs may queue up, it's possible to
@@ -104,6 +105,20 @@ type limitRunsTo struct {
104
105
runCount uint
105
106
}
106
107
108
+ // -----------------------------------------------
109
+ // -----------------------------------------------
110
+ // --------------- Custom Cron -------------------
111
+ // -----------------------------------------------
112
+ // -----------------------------------------------
113
+
114
+ // Cron defines the interface that must be
115
+ // implemented to provide a custom cron implementation for
116
+ // the job. Pass in the implementation using the JobOption WithCronImplementation.
117
+ type Cron interface {
118
+ IsValid (crontab string , location * time.Location , now time.Time ) error
119
+ Next (lastRun time.Time ) time.Time
120
+ }
121
+
107
122
// -----------------------------------------------
108
123
// -----------------------------------------------
109
124
// --------------- Job Variants ------------------
@@ -116,29 +131,37 @@ type JobDefinition interface {
116
131
setup (j * internalJob , l * time.Location , now time.Time ) error
117
132
}
118
133
119
- var _ JobDefinition = ( * cronJobDefinition )( nil )
134
+ // Default cron implementation
120
135
121
- type cronJobDefinition struct {
122
- crontab string
123
- withSeconds bool
136
+ func newDefaultCronImplementation (withSeconds bool ) Cron {
137
+ return & defaultCron {
138
+ withSeconds : withSeconds ,
139
+ }
124
140
}
125
141
126
- func (c cronJobDefinition ) setup (j * internalJob , location * time.Location , now time.Time ) error {
142
+ var _ Cron = (* defaultCron )(nil )
143
+
144
+ type defaultCron struct {
145
+ cronSchedule cron.Schedule
146
+ withSeconds bool
147
+ }
148
+
149
+ func (r * defaultCron ) IsValid (crontab string , location * time.Location , now time.Time ) error {
127
150
var withLocation string
128
- if strings .HasPrefix (c . crontab , "TZ=" ) || strings .HasPrefix (c . crontab , "CRON_TZ=" ) {
129
- withLocation = c . crontab
151
+ if strings .HasPrefix (crontab , "TZ=" ) || strings .HasPrefix (crontab , "CRON_TZ=" ) {
152
+ withLocation = crontab
130
153
} else {
131
154
// since the user didn't provide a timezone default to the location
132
155
// passed in by the scheduler. Default: time.Local
133
- withLocation = fmt .Sprintf ("CRON_TZ=%s %s" , location .String (), c . crontab )
156
+ withLocation = fmt .Sprintf ("CRON_TZ=%s %s" , location .String (), crontab )
134
157
}
135
158
136
159
var (
137
160
cronSchedule cron.Schedule
138
161
err error
139
162
)
140
163
141
- if c .withSeconds {
164
+ if r .withSeconds {
142
165
p := cron .NewParser (cron .SecondOptional | cron .Minute | cron .Hour | cron .Dom | cron .Month | cron .Dow | cron .Descriptor )
143
166
cronSchedule , err = p .Parse (withLocation )
144
167
} else {
@@ -150,8 +173,32 @@ func (c cronJobDefinition) setup(j *internalJob, location *time.Location, now ti
150
173
if cronSchedule .Next (now ).IsZero () {
151
174
return ErrCronJobInvalid
152
175
}
176
+ r .cronSchedule = cronSchedule
177
+ return nil
178
+ }
153
179
154
- j .jobSchedule = & cronJob {cronSchedule : cronSchedule }
180
+ func (r * defaultCron ) Next (lastRun time.Time ) time.Time {
181
+ return r .cronSchedule .Next (lastRun )
182
+ }
183
+
184
+ // default cron job implimentation
185
+ var _ JobDefinition = (* cronJobDefinition )(nil )
186
+
187
+ type cronJobDefinition struct {
188
+ crontab string
189
+ cron Cron
190
+ }
191
+
192
+ func (c cronJobDefinition ) setup (j * internalJob , location * time.Location , now time.Time ) error {
193
+ if j .cron != nil {
194
+ c .cron = j .cron
195
+ }
196
+
197
+ if err := c .cron .IsValid (c .crontab , location , now ); err != nil {
198
+ return err
199
+ }
200
+
201
+ j .jobSchedule = & cronJob {crontab : c .crontab , cronSchedule : c .cron }
155
202
return nil
156
203
}
157
204
@@ -163,8 +210,8 @@ func (c cronJobDefinition) setup(j *internalJob, location *time.Location, now ti
163
210
// `CRON_TZ=America/Chicago * * * * *`
164
211
func CronJob (crontab string , withSeconds bool ) JobDefinition {
165
212
return cronJobDefinition {
166
- crontab : crontab ,
167
- withSeconds : withSeconds ,
213
+ crontab : crontab ,
214
+ cron : newDefaultCronImplementation ( withSeconds ) ,
168
215
}
169
216
}
170
217
@@ -608,6 +655,15 @@ func WithName(name string) JobOption {
608
655
}
609
656
}
610
657
658
+ // WithCronImplementation sets the custom Cron implementation for the job.
659
+ // This is only utilized for the CronJob type.
660
+ func WithCronImplementation (c Cron ) JobOption {
661
+ return func (j * internalJob , _ time.Time ) error {
662
+ j .cron = c
663
+ return nil
664
+ }
665
+ }
666
+
611
667
// WithSingletonMode keeps the job from running again if it is already running.
612
668
// This is useful for jobs that should not overlap, and that occasionally
613
669
// (but not consistently) run longer than the interval between job runs.
@@ -818,7 +874,8 @@ type jobSchedule interface {
818
874
var _ jobSchedule = (* cronJob )(nil )
819
875
820
876
type cronJob struct {
821
- cronSchedule cron.Schedule
877
+ crontab string
878
+ cronSchedule Cron
822
879
}
823
880
824
881
func (j * cronJob ) next (lastRun time.Time ) time.Time {
0 commit comments