64 lines
1.3 KiB
Go
64 lines
1.3 KiB
Go
package scheduler
|
|
|
|
import (
|
|
"context"
|
|
"log/slog"
|
|
"time"
|
|
|
|
"github.com/cereda-systems/nexus-scanner/internal/module"
|
|
)
|
|
|
|
// Scheduler runs registered modules at their configured intervals.
|
|
type Scheduler struct {
|
|
registry *module.Registry
|
|
}
|
|
|
|
// New returns a new Scheduler backed by the given registry.
|
|
func New(registry *module.Registry) *Scheduler {
|
|
return &Scheduler{registry: registry}
|
|
}
|
|
|
|
// Run starts all modules in background goroutines and blocks until ctx is cancelled.
|
|
func (s *Scheduler) Run(ctx context.Context) {
|
|
for _, m := range s.registry.All() {
|
|
go s.runModule(ctx, m)
|
|
}
|
|
<-ctx.Done()
|
|
}
|
|
|
|
func (s *Scheduler) runModule(ctx context.Context, m module.Module) {
|
|
log := slog.With("module", m.Name())
|
|
|
|
// Run immediately on startup.
|
|
s.execute(ctx, m, log)
|
|
|
|
// If interval is zero, run once and stop.
|
|
if m.Interval() == 0 {
|
|
return
|
|
}
|
|
|
|
ticker := time.NewTicker(m.Interval())
|
|
defer ticker.Stop()
|
|
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
return
|
|
case <-ticker.C:
|
|
s.execute(ctx, m, log)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *Scheduler) execute(ctx context.Context, m module.Module, log *slog.Logger) {
|
|
log.Info("run started")
|
|
start := time.Now()
|
|
|
|
if err := m.Run(ctx); err != nil {
|
|
log.Error("run failed", "err", err, "elapsed", time.Since(start).Round(time.Millisecond))
|
|
return
|
|
}
|
|
|
|
log.Info("run completed", "elapsed", time.Since(start).Round(time.Millisecond))
|
|
}
|