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

feat:custom-cron interface for own custom cron implimentation #834

Merged
merged 7 commits into from
Feb 25, 2025
Merged
86 changes: 70 additions & 16 deletions job.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
id uuid.UUID
name string
tags []string
cron Cron
jobSchedule

// as some jobs may queue up, it's possible to
Expand Down Expand Up @@ -104,6 +105,20 @@
runCount uint
}

// -----------------------------------------------
// -----------------------------------------------
// --------------- Custom Cron ------------------
// -----------------------------------------------
// -----------------------------------------------

// Cron defines the interface that must be
// implemented to create a cron.

type Cron interface {

Check failure on line 117 in job.go

View workflow job for this annotation

GitHub Actions / lint and test (1.21)

exported: exported type Cron should have comment or be unexported (revive)

Check failure on line 117 in job.go

View workflow job for this annotation

GitHub Actions / lint and test (1.22)

exported: exported type Cron should have comment or be unexported (revive)

Check failure on line 117 in job.go

View workflow job for this annotation

GitHub Actions / lint and test (1.23)

exported: exported type Cron should have comment or be unexported (revive)
IsValid(string) bool
Next(string, time.Time) time.Time
}

// -----------------------------------------------
// -----------------------------------------------
// --------------- Job Variants ------------------
Expand All @@ -116,42 +131,72 @@
setup(j *internalJob, l *time.Location, now time.Time) error
}

var _ JobDefinition = (*cronJobDefinition)(nil)
// Default cron implementation using robfig

type cronJobDefinition struct {
crontab string
withSeconds bool
func newDefaultCronImplementation(withSeconds bool) Cron {
return &RobfigCron{
withSeconds: withSeconds,
}
}

func (c cronJobDefinition) setup(j *internalJob, location *time.Location, now time.Time) error {
type RobfigCron struct {

Check failure on line 142 in job.go

View workflow job for this annotation

GitHub Actions / lint and test (1.21)

exported: exported type RobfigCron should have comment or be unexported (revive)

Check failure on line 142 in job.go

View workflow job for this annotation

GitHub Actions / lint and test (1.22)

exported: exported type RobfigCron should have comment or be unexported (revive)

Check failure on line 142 in job.go

View workflow job for this annotation

GitHub Actions / lint and test (1.23)

exported: exported type RobfigCron should have comment or be unexported (revive)
cronSchedule cron.Schedule
withSeconds bool
}

func (r *RobfigCron) IsValid(crontab string) bool {

Check failure on line 147 in job.go

View workflow job for this annotation

GitHub Actions / lint and test (1.21)

exported: exported method RobfigCron.IsValid should have comment or be unexported (revive)

Check failure on line 147 in job.go

View workflow job for this annotation

GitHub Actions / lint and test (1.22)

exported: exported method RobfigCron.IsValid should have comment or be unexported (revive)

Check failure on line 147 in job.go

View workflow job for this annotation

GitHub Actions / lint and test (1.23)

exported: exported method RobfigCron.IsValid should have comment or be unexported (revive)
var withLocation string
if strings.HasPrefix(c.crontab, "TZ=") || strings.HasPrefix(c.crontab, "CRON_TZ=") {
withLocation = c.crontab
if strings.HasPrefix(crontab, "TZ=") || strings.HasPrefix(crontab, "CRON_TZ=") {
withLocation = crontab
} else {
// since the user didn't provide a timezone default to the location
// passed in by the scheduler. Default: time.Local
withLocation = fmt.Sprintf("CRON_TZ=%s %s", location.String(), c.crontab)
withLocation = fmt.Sprintf("CRON_TZ=%s %s", time.Local, crontab)
}

var (
cronSchedule cron.Schedule
err error
)

if c.withSeconds {
if r.withSeconds {
p := cron.NewParser(cron.SecondOptional | cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow | cron.Descriptor)
cronSchedule, err = p.Parse(withLocation)
} else {
cronSchedule, err = cron.ParseStandard(withLocation)
}
if err != nil {
return errors.Join(ErrCronJobParse, err)
return false
}
if cronSchedule.Next(time.Now()).IsZero() {
return false
}
if cronSchedule.Next(now).IsZero() {
r.cronSchedule = cronSchedule
return true
}

func (r *RobfigCron) Next(crontab string, lastRun time.Time) time.Time {

Check failure on line 178 in job.go

View workflow job for this annotation

GitHub Actions / lint and test (1.21)

exported: exported method RobfigCron.Next should have comment or be unexported (revive)

Check failure on line 178 in job.go

View workflow job for this annotation

GitHub Actions / lint and test (1.22)

unused-parameter: parameter 'crontab' seems to be unused, consider removing or renaming it as _ (revive)

Check failure on line 178 in job.go

View workflow job for this annotation

GitHub Actions / lint and test (1.23)

unused-parameter: parameter 'crontab' seems to be unused, consider removing or renaming it as _ (revive)
return r.cronSchedule.Next(lastRun)
}

// default cron job implimentation
var _ JobDefinition = (*cronJobDefinition)(nil)

type cronJobDefinition struct {
crontab string
cron Cron
}

func (c cronJobDefinition) setup(j *internalJob, location *time.Location, _ time.Time) error {

Check failure on line 190 in job.go

View workflow job for this annotation

GitHub Actions / lint and test (1.21)

unused-parameter: parameter 'location' seems to be unused, consider removing or renaming it as _ (revive)

Check failure on line 190 in job.go

View workflow job for this annotation

GitHub Actions / lint and test (1.22)

unused-parameter: parameter 'location' seems to be unused, consider removing or renaming it as _ (revive)

Check failure on line 190 in job.go

View workflow job for this annotation

GitHub Actions / lint and test (1.23)

unused-parameter: parameter 'location' seems to be unused, consider removing or renaming it as _ (revive)
if j.cron != nil {
c.cron = j.cron
}

if !c.cron.IsValid(c.crontab) {
return ErrCronJobInvalid
}

j.jobSchedule = &cronJob{cronSchedule: cronSchedule}
j.jobSchedule = &cronJob{crontab: c.crontab, cronSchedule: c.cron}
return nil
}

Expand All @@ -163,8 +208,8 @@
// `CRON_TZ=America/Chicago * * * * *`
func CronJob(crontab string, withSeconds bool) JobDefinition {
return cronJobDefinition{
crontab: crontab,
withSeconds: withSeconds,
crontab: crontab,
cron: newDefaultCronImplementation(withSeconds),
}
}

Expand Down Expand Up @@ -608,6 +653,14 @@
}
}

// JobOption to set custom Cron implementation

Check failure on line 656 in job.go

View workflow job for this annotation

GitHub Actions / lint and test (1.21)

exported: comment on exported function WithCronImplementation should be of the form "WithCronImplementation ..." (revive)

Check failure on line 656 in job.go

View workflow job for this annotation

GitHub Actions / lint and test (1.22)

exported: comment on exported function WithCronImplementation should be of the form "WithCronImplementation ..." (revive)

Check failure on line 656 in job.go

View workflow job for this annotation

GitHub Actions / lint and test (1.23)

exported: comment on exported function WithCronImplementation should be of the form "WithCronImplementation ..." (revive)
func WithCronImplementation(c Cron) JobOption {
return func(j *internalJob, _ time.Time) error {
j.cron = c
return nil
}
}

// WithSingletonMode keeps the job from running again if it is already running.
// This is useful for jobs that should not overlap, and that occasionally
// (but not consistently) run longer than the interval between job runs.
Expand Down Expand Up @@ -818,11 +871,12 @@
var _ jobSchedule = (*cronJob)(nil)

type cronJob struct {
cronSchedule cron.Schedule
crontab string
cronSchedule Cron
}

func (j *cronJob) next(lastRun time.Time) time.Time {
return j.cronSchedule.Next(lastRun)
return j.cronSchedule.Next(j.crontab, lastRun)
}

var _ jobSchedule = (*durationJob)(nil)
Expand Down
Loading