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

95 lines
1.8 KiB
Go

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