Files
silo-server/internal/taskmanager/triggers/weekly.go
T

98 lines
2.0 KiB
Go

package triggers
import (
"fmt"
"sync"
"time"
"github.com/Silo-Server/silo-server/internal/taskmanager"
)
// WeeklyTrigger fires at a specific time on a specific day of the week.
type WeeklyTrigger struct {
cfg taskmanager.TriggerConfig
dayOfWeek time.Weekday
hour int
minute int
ch chan struct{}
nextRun time.Time
timer *time.Timer
stopCh chan struct{}
mu sync.Mutex
}
func NewWeeklyTrigger(cfg taskmanager.TriggerConfig) *WeeklyTrigger {
var h, m int
fmt.Sscanf(cfg.TimeOfDay, "%d:%d", &h, &m)
return &WeeklyTrigger{
cfg: cfg,
dayOfWeek: time.Weekday(cfg.DayOfWeek),
hour: h,
minute: m,
ch: make(chan struct{}, 1),
}
}
func (w *WeeklyTrigger) calcNextRun(now time.Time) time.Time {
daysAhead := (int(w.dayOfWeek) - int(now.Weekday()) + 7) % 7
target := time.Date(now.Year(), now.Month(), now.Day()+daysAhead, w.hour, w.minute, 0, 0, now.Location())
if daysAhead == 0 && !target.After(now) {
target = target.Add(7 * 24 * time.Hour)
}
return target
}
func (w *WeeklyTrigger) Start(_ *taskmanager.ExecutionResult) {
w.mu.Lock()
defer w.mu.Unlock()
// Drain any stale signal from a previous timer fire.
select {
case <-w.ch:
default:
}
w.stopCh = make(chan struct{})
w.nextRun = w.calcNextRun(time.Now())
w.timer = time.NewTimer(time.Until(w.nextRun))
go func() {
select {
case <-w.stopCh:
if !w.timer.Stop() {
select {
case <-w.timer.C:
default:
}
}
return
case <-w.timer.C:
select {
case w.ch <- struct{}{}:
default:
}
}
}()
}
func (w *WeeklyTrigger) Stop() {
w.mu.Lock()
defer w.mu.Unlock()
if w.stopCh != nil {
select {
case <-w.stopCh:
default:
close(w.stopCh)
}
}
}
func (w *WeeklyTrigger) NextRunTime() time.Time {
w.mu.Lock()
defer w.mu.Unlock()
return w.nextRun
}
func (w *WeeklyTrigger) Config() taskmanager.TriggerConfig { return w.cfg }
func (w *WeeklyTrigger) C() <-chan struct{} { return w.ch }