forked from actions/actions-runner-controller
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Foundation for ScheduledOverrides (actions#513)
Adds two types `RecurrenceRule` and `Period` and one function `MatchSchedule` as the foundation for building the upcoming ScheduledOverrides feature. Ref actions#484
- Loading branch information
Showing
4 changed files
with
732 additions
and
0 deletions.
There are no files selected for viewing
122 changes: 122 additions & 0 deletions
122
controllers/horizontalrunnerautoscaler_scheduled_overrides.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
package controllers | ||
|
||
import ( | ||
"fmt" | ||
"time" | ||
|
||
"github.com/teambition/rrule-go" | ||
) | ||
|
||
type RecurrenceRule struct { | ||
Frequency string | ||
UntilTime time.Time | ||
} | ||
|
||
type Period struct { | ||
StartTime time.Time | ||
EndTime time.Time | ||
} | ||
|
||
func (r *Period) String() string { | ||
if r == nil { | ||
return "" | ||
} | ||
|
||
return r.StartTime.Format(time.RFC3339) + "-" + r.EndTime.Format(time.RFC3339) | ||
} | ||
|
||
func MatchSchedule(now time.Time, startTime, endTime time.Time, recurrenceRule RecurrenceRule) (*Period, *Period, error) { | ||
return calculateActiveAndUpcomingRecurringPeriods( | ||
now, | ||
startTime, | ||
endTime, | ||
recurrenceRule.Frequency, | ||
recurrenceRule.UntilTime, | ||
) | ||
} | ||
|
||
func calculateActiveAndUpcomingRecurringPeriods(now, startTime, endTime time.Time, frequency string, untilTime time.Time) (*Period, *Period, error) { | ||
var freqValue rrule.Frequency | ||
|
||
var freqDurationDay int | ||
var freqDurationMonth int | ||
var freqDurationYear int | ||
|
||
switch frequency { | ||
case "Daily": | ||
freqValue = rrule.DAILY | ||
freqDurationDay = 1 | ||
case "Weekly": | ||
freqValue = rrule.WEEKLY | ||
freqDurationDay = 7 | ||
case "Monthly": | ||
freqValue = rrule.MONTHLY | ||
freqDurationMonth = 1 | ||
case "Yearly": | ||
freqValue = rrule.YEARLY | ||
freqDurationYear = 1 | ||
case "": | ||
if now.Before(startTime) { | ||
return nil, &Period{StartTime: startTime, EndTime: endTime}, nil | ||
} | ||
|
||
if now.Before(endTime) { | ||
return &Period{StartTime: startTime, EndTime: endTime}, nil, nil | ||
} | ||
|
||
return nil, nil, nil | ||
default: | ||
return nil, nil, fmt.Errorf(`invalid freq %q: It must be one of "Daily", "Weekly", "Monthly", and "Yearly"`, frequency) | ||
} | ||
|
||
freqDurationLater := time.Date( | ||
now.Year()+freqDurationYear, | ||
time.Month(int(now.Month())+freqDurationMonth), | ||
now.Day()+freqDurationDay, | ||
now.Hour(), now.Minute(), now.Second(), now.Nanosecond(), now.Location(), | ||
) | ||
|
||
freqDuration := freqDurationLater.Sub(now) | ||
|
||
overrideDuration := endTime.Sub(startTime) | ||
if overrideDuration > freqDuration { | ||
return nil, nil, fmt.Errorf("override's duration %s must be equal to sor shorter than the duration implied by freq %q (%s)", overrideDuration, frequency, freqDuration) | ||
} | ||
|
||
rrule, err := rrule.NewRRule(rrule.ROption{ | ||
Freq: freqValue, | ||
Dtstart: startTime, | ||
Until: untilTime, | ||
}) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
|
||
overrideDurationBefore := now.Add(-overrideDuration + 1) | ||
activeOverrideStarts := rrule.Between(overrideDurationBefore, now, true) | ||
|
||
var active *Period | ||
|
||
if len(activeOverrideStarts) > 1 { | ||
return nil, nil, fmt.Errorf("[bug] unexpted number of active overrides found: %v", activeOverrideStarts) | ||
} else if len(activeOverrideStarts) == 1 { | ||
active = &Period{ | ||
StartTime: activeOverrideStarts[0], | ||
EndTime: activeOverrideStarts[0].Add(overrideDuration), | ||
} | ||
} | ||
|
||
oneSecondLater := now.Add(1) | ||
upcomingOverrideStarts := rrule.Between(oneSecondLater, freqDurationLater, true) | ||
|
||
var next *Period | ||
|
||
if len(upcomingOverrideStarts) > 0 { | ||
next = &Period{ | ||
StartTime: upcomingOverrideStarts[0], | ||
EndTime: upcomingOverrideStarts[0].Add(overrideDuration), | ||
} | ||
} | ||
|
||
return active, next, nil | ||
} |
Oops, something went wrong.