Skip to content

Commit

Permalink
feat: use hashicorp/cronexpr for cron
Browse files Browse the repository at this point in the history
This replaces our cron calculation with those provided by a 3rd party library.

Unfortunatly we still need to do our own parsing however, as we support additional syntax, and other parts of the code expect to be able to parse the Pattern using participle.

closess #1744
  • Loading branch information
stuartwdouglas committed Jul 22, 2024
1 parent f515a3a commit 5e772ca
Show file tree
Hide file tree
Showing 8 changed files with 43 additions and 469 deletions.
12 changes: 8 additions & 4 deletions backend/controller/cronjobs/cronjobs.go
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ func (s *Service) watchForUpdates(ctx context.Context) {
now := s.clock.Now()
next := now.Add(time.Hour) // should never be reached, expect a different signal long beforehand
for _, j := range state.jobs {
if possibleNext, err := s.nextAttemptForJob(j, state, false); err == nil && possibleNext.Before(next) {
if possibleNext, err := s.nextAttemptForJob(j, state, now,false); err == nil && possibleNext.Before(next) {
next = possibleNext
}
}
Expand All @@ -329,8 +329,11 @@ func (s *Service) watchForUpdates(ctx context.Context) {
return
case <-s.clock.After(next.Sub(now)):
// Try starting jobs in db
// note that we use next here are the current time
// as if there is a pause of over a second we could miss jobs if we use the current time
// this is very unlikely to happen, but if it did it would be hard to diagnose
jobsToAttempt := slices.Filter(state.jobs, func(j model.CronJob) bool {
if n, err := s.nextAttemptForJob(j, state, true); err == nil {
if n, err := s.nextAttemptForJob(j, state, next,true); err == nil {
return !n.After(s.clock.Now().UTC())
}
return false
Expand Down Expand Up @@ -386,7 +389,8 @@ func (s *Service) watchForUpdates(ctx context.Context) {
}
}

func (s *Service) nextAttemptForJob(job model.CronJob, state *state, allowsNow bool) (time.Time, error) {
func (s *Service) nextAttemptForJob(job model.CronJob, state *state, currentTime time.Time, allowsNow bool) (time.Time, error) {
currentTime = currentTime.UTC()
if !s.isResponsibleForJob(job, state) {
return s.clock.Now(), fmt.Errorf("controller is not responsible for job")
}
Expand All @@ -401,7 +405,7 @@ func (s *Service) nextAttemptForJob(job model.CronJob, state *state, allowsNow b
if err != nil {
return s.clock.Now(), fmt.Errorf("failed to parse cron schedule %q", job.Schedule)
}
next, err := cron.NextAfter(pattern, s.clock.Now().UTC(), allowsNow)
next, err := cron.NextAfter(pattern, currentTime, allowsNow)
if err == nil {
return next, nil
}
Expand Down
1 change: 1 addition & 0 deletions examples/go/echo/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ require (
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/hashicorp/cronexpr v1.1.2 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jackc/pgx/v5 v5.6.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions examples/go/echo/go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ require (
github.com/docker/go-connections v0.5.0
github.com/go-logr/logr v1.4.2
github.com/google/uuid v1.6.0
github.com/hashicorp/cronexpr v1.1.2
github.com/jackc/pgerrcode v0.0.0-20240316143900-6e2875d9b438
github.com/jackc/pgx/v5 v5.6.0
github.com/jellydator/ttlcache/v3 v3.2.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 5e772ca

Please sign in to comment.