
Replace old used-to-be-GORM datastructures (#104305) with sqlc-generated structs. This also makes it possible to use more specific structs that are more taylored to the specific queries, increasing efficiency. This commit deals with the worker sleep schedule. Functional changes are kept to a minimum, as the API still serves the same data. Because this work covers so much of Flamenco's code, it's been split up into different commits. Each commit brings Flamenco to a state where it compiles and unit tests pass. Only the result of the final commit has actually been tested properly. Ref: #104343
106 lines
2.9 KiB
Go
106 lines
2.9 KiB
Go
package sleep_scheduler
|
|
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
import (
|
|
"strings"
|
|
"time"
|
|
|
|
"projects.blender.org/studio/flamenco/internal/manager/persistence"
|
|
"projects.blender.org/studio/flamenco/pkg/api"
|
|
"projects.blender.org/studio/flamenco/pkg/time_of_day"
|
|
)
|
|
|
|
// scheduledWorkerStatus returns the expected worker status at the given date/time.
|
|
func scheduledWorkerStatus(now time.Time, sched *persistence.SleepSchedule) api.WorkerStatus {
|
|
if sched == nil {
|
|
// If there is no schedule at all, the worker should be awake.
|
|
return api.WorkerStatusAwake
|
|
}
|
|
|
|
tod := time_of_day.MakeTimeOfDay(now)
|
|
|
|
if !sched.IsActive {
|
|
return api.WorkerStatusAwake
|
|
}
|
|
|
|
if sched.DaysOfWeek != "" {
|
|
weekdayName := strings.ToLower(now.Weekday().String()[:2])
|
|
if !strings.Contains(sched.DaysOfWeek, weekdayName) {
|
|
// There are days configured, and today is not a sleeping day.
|
|
return api.WorkerStatusAwake
|
|
}
|
|
}
|
|
|
|
beforeStart := sched.StartTime.HasValue() && tod.IsBefore(sched.StartTime)
|
|
afterEnd := sched.EndTime.HasValue() && !tod.IsBefore(sched.EndTime)
|
|
|
|
if beforeStart || afterEnd {
|
|
// Outside sleeping time.
|
|
return api.WorkerStatusAwake
|
|
}
|
|
|
|
return api.WorkerStatusAsleep
|
|
}
|
|
|
|
func cleanupDaysOfWeek(daysOfWeek string) string {
|
|
trimmed := strings.TrimSpace(daysOfWeek)
|
|
if trimmed == "" {
|
|
return ""
|
|
}
|
|
|
|
daynames := strings.Fields(trimmed)
|
|
for idx, name := range daynames {
|
|
daynames[idx] = strings.ToLower(strings.TrimSpace(name))[:2]
|
|
}
|
|
return strings.Join(daynames, " ")
|
|
}
|
|
|
|
// Return a timestamp when the next scheck for this schedule is due.
|
|
func calculateNextCheck(now time.Time, schedule persistence.SleepSchedule) time.Time {
|
|
// calcNext returns the given time of day on "today" if that hasn't passed
|
|
// yet, otherwise on "tomorrow".
|
|
calcNext := func(tod time_of_day.TimeOfDay) time.Time {
|
|
nextCheck := tod.OnDate(now).In(time.Local)
|
|
if nextCheck.Before(now) {
|
|
nextCheck = nextCheck.AddDate(0, 0, 1)
|
|
}
|
|
return nextCheck
|
|
}
|
|
|
|
nextChecks := []time.Time{
|
|
// Always check at the end of the day.
|
|
endOfDay(now),
|
|
}
|
|
|
|
// No start time means "start of the day", which is already covered by
|
|
// yesterday's "end of the day" check.
|
|
if schedule.StartTime.HasValue() {
|
|
nextChecks = append(nextChecks, calcNext(schedule.StartTime))
|
|
}
|
|
// No end time means "end of the day", which is already covered by today's
|
|
// "end of the day" check.
|
|
if schedule.EndTime.HasValue() {
|
|
nextChecks = append(nextChecks, calcNext(schedule.EndTime))
|
|
}
|
|
|
|
next := earliestTime(nextChecks)
|
|
return next
|
|
}
|
|
|
|
func earliestTime(timestamps []time.Time) time.Time {
|
|
earliest := timestamps[0]
|
|
for _, timestamp := range timestamps[1:] {
|
|
if timestamp.Before(earliest) {
|
|
earliest = timestamp
|
|
}
|
|
}
|
|
return earliest
|
|
}
|
|
|
|
// endOfDay returns the next midnight at UTC.
|
|
func endOfDay(now time.Time) time.Time {
|
|
startOfDay := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local)
|
|
return startOfDay.AddDate(0, 0, 1)
|
|
}
|