98 lines
1.8 KiB
Go
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 }
|