Files
coder/coderd/schedule/autostart.go
Danielle Maywood e21a301682 fix: make GetWorkspacesEligibleForTransition return even less false positives (#15594)
Relates to https://github.com/coder/coder/issues/15082

Further to https://github.com/coder/coder/pull/15429, this reduces the
amount of false-positives returned by the 'is eligible for autostart'
part of the query. We achieve this by calculating the 'next start at'
time of the workspace, storing it in the database, and using it in our
`GetWorkspacesEligibleForTransition` query.

The prior implementation of the 'is eligible for autostart' query would
return _all_ workspaces that at some point in the future _might_ be
eligible for autostart. This now ensures we only return workspaces that
_should_ be eligible for autostart.

We also now pass `currentTick` instead of `t` to the
`GetWorkspacesEligibleForTransition` query as otherwise we'll have one
round of workspaces that are skipped by `isEligibleForTransition` due to
`currentTick` being a truncated version of `t`.
2024-12-02 21:02:36 +00:00

51 lines
1.8 KiB
Go

package schedule
import (
"time"
"golang.org/x/xerrors"
"github.com/coder/coder/v2/coderd/schedule/cron"
)
var ErrNoAllowedAutostart = xerrors.New("no allowed autostart")
// NextAutostart takes the workspace and template schedule and returns the next autostart schedule
// after "at". The boolean returned is if the autostart should be allowed to start based on the template
// schedule.
func NextAutostart(at time.Time, wsSchedule string, templateSchedule TemplateScheduleOptions) (time.Time, bool) {
sched, err := cron.Weekly(wsSchedule)
if err != nil {
return time.Time{}, false
}
// Round down to the nearest minute, as this is the finest granularity cron supports.
// Truncate is probably not necessary here, but doing it anyway to be sure.
nextTransition := sched.Next(at).Truncate(time.Minute)
// The nextTransition is when the auto start should kick off. If it lands on a
// forbidden day, do not allow the auto start. We use the time location of the
// schedule to determine the weekday. So if "Saturday" is disallowed, the
// definition of "Saturday" depends on the location of the schedule.
zonedTransition := nextTransition.In(sched.Location())
allowed := templateSchedule.AutostartRequirement.DaysMap()[zonedTransition.Weekday()]
return zonedTransition, allowed
}
func NextAllowedAutostart(at time.Time, wsSchedule string, templateSchedule TemplateScheduleOptions) (time.Time, error) {
next := at
// Our cron schedules work on a weekly basis, so to ensure we've exhausted all
// possible autostart times we need to check up to 7 days worth of autostarts.
for next.Sub(at) < 7*24*time.Hour {
var valid bool
next, valid = NextAutostart(next, wsSchedule, templateSchedule)
if valid {
return next, nil
}
}
return time.Time{}, ErrNoAllowedAutostart
}