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

98 lines
1.8 KiB
Go

package triggers
import (
"sync"
"time"
"github.com/Silo-Server/silo-server/internal/taskmanager"
)
// IntervalTrigger fires every N milliseconds, measured from completion of the
// previous run (not from start). If no previous run exists, it fires
// interval-after-Start().
type IntervalTrigger struct {
cfg taskmanager.TriggerConfig
interval time.Duration
ch chan struct{}
nextRun time.Time
timer *time.Timer
stopCh chan struct{}
mu sync.Mutex
}
func NewIntervalTrigger(cfg taskmanager.TriggerConfig) *IntervalTrigger {
return &IntervalTrigger{
cfg: cfg,
interval: time.Duration(cfg.IntervalMs) * time.Millisecond,
ch: make(chan struct{}, 1),
}
}
func (t *IntervalTrigger) Start(lastResult *taskmanager.ExecutionResult) {
t.mu.Lock()
defer t.mu.Unlock()
// Drain any stale signal from a previous timer fire.
select {
case <-t.ch:
default:
}
t.stopCh = make(chan struct{})
var base time.Time
if lastResult != nil && !lastResult.CompletedAt.IsZero() {
base = lastResult.CompletedAt
} else {
base = time.Now()
}
t.nextRun = base.Add(t.interval)
delay := time.Until(t.nextRun)
if delay < 0 {
delay = 0
t.nextRun = time.Now()
}
t.timer = time.NewTimer(delay)
go func() {
select {
case <-t.stopCh:
if !t.timer.Stop() {
select {
case <-t.timer.C:
default:
}
}
return
case <-t.timer.C:
select {
case t.ch <- struct{}{}:
default:
}
}
}()
}
func (t *IntervalTrigger) Stop() {
t.mu.Lock()
defer t.mu.Unlock()
if t.stopCh != nil {
select {
case <-t.stopCh:
default:
close(t.stopCh)
}
}
}
func (t *IntervalTrigger) NextRunTime() time.Time {
t.mu.Lock()
defer t.mu.Unlock()
return t.nextRun
}
func (t *IntervalTrigger) Config() taskmanager.TriggerConfig { return t.cfg }
func (t *IntervalTrigger) C() <-chan struct{} { return t.ch }