feat(scheduler): Reconciler iteriert alle Screens + resolveDesiredState
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
e76f89798f
commit
81711f2f3d
1 changed files with 29 additions and 19 deletions
|
|
@ -25,6 +25,11 @@ type DisplayStateGetter interface {
|
|||
GetDisplayState(ctx context.Context, screenID string) (string, error)
|
||||
}
|
||||
|
||||
// AllScreensLister lädt alle bekannten Screens.
|
||||
type AllScreensLister interface {
|
||||
ListAll(ctx context.Context) ([]*store.Screen, error)
|
||||
}
|
||||
|
||||
// Run startet den Scheduler-Loop. Blockiert bis ctx abgebrochen wird.
|
||||
func Run(ctx context.Context, schedules *store.ScreenScheduleStore, screens ScreenSlugGetter, notifier DisplayCommander) {
|
||||
ticker := time.NewTicker(1 * time.Minute)
|
||||
|
|
@ -41,39 +46,50 @@ func Run(ctx context.Context, schedules *store.ScreenScheduleStore, screens Scre
|
|||
}
|
||||
|
||||
// Reconcile läuft alle 5 Minuten und gleicht Ist- und Soll-Zustand ab.
|
||||
func Reconcile(ctx context.Context, schedules *store.ScreenScheduleStore, screens ScreenSlugGetter, states DisplayStateGetter, notifier DisplayCommander) {
|
||||
func Reconcile(ctx context.Context, schedules *store.ScreenScheduleStore, screens AllScreensLister, states DisplayStateGetter, globalOverrides *store.GlobalOverrideStore, notifier DisplayCommander) {
|
||||
ticker := time.NewTicker(5 * time.Minute)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
reconcile(ctx, schedules, screens, states, notifier)
|
||||
reconcile(ctx, schedules, screens, states, globalOverrides, notifier)
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func reconcile(ctx context.Context, schedules *store.ScreenScheduleStore, screens ScreenSlugGetter, states DisplayStateGetter, notifier DisplayCommander) {
|
||||
now := time.Now().Format("15:04")
|
||||
func reconcile(ctx context.Context, schedules *store.ScreenScheduleStore, allScreens AllScreensLister, states DisplayStateGetter, globalOverrides *store.GlobalOverrideStore, notifier DisplayCommander) {
|
||||
now := time.Now()
|
||||
|
||||
enabled, err := schedules.ListEnabled(ctx)
|
||||
screenList, err := allScreens.ListAll(ctx)
|
||||
if err != nil {
|
||||
slog.Error("reconciler: list enabled schedules failed", "err", err)
|
||||
slog.Error("reconciler: list all screens failed", "err", err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, sc := range enabled {
|
||||
if sc.PowerOnTime == "" || sc.PowerOffTime == "" {
|
||||
globalOverride, err := globalOverrides.Get(ctx)
|
||||
if err != nil {
|
||||
slog.Warn("reconciler: get global override failed", "err", err)
|
||||
// nicht fatal — ohne Override fortfahren
|
||||
}
|
||||
|
||||
for _, screen := range screenList {
|
||||
sc, err := schedules.Get(ctx, screen.ID)
|
||||
if err != nil {
|
||||
slog.Warn("reconciler: get schedule failed", "screen_id", screen.ID, "err", err)
|
||||
continue
|
||||
}
|
||||
|
||||
want := desiredState(sc.PowerOnTime, sc.PowerOffTime, now)
|
||||
want, shouldControl := resolveDesiredState(*sc, globalOverride, now)
|
||||
if !shouldControl {
|
||||
continue
|
||||
}
|
||||
|
||||
got, err := states.GetDisplayState(ctx, sc.ScreenID)
|
||||
got, err := states.GetDisplayState(ctx, screen.ID)
|
||||
if err != nil {
|
||||
slog.Warn("reconciler: get display state failed", "screen_id", sc.ScreenID, "err", err)
|
||||
slog.Warn("reconciler: get display state failed", "screen_id", screen.ID, "err", err)
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
@ -81,17 +97,11 @@ func reconcile(ctx context.Context, schedules *store.ScreenScheduleStore, screen
|
|||
continue
|
||||
}
|
||||
|
||||
screen, err := screens.GetByID(ctx, sc.ScreenID)
|
||||
if err != nil {
|
||||
slog.Warn("reconciler: screen not found", "screen_id", sc.ScreenID, "err", err)
|
||||
continue
|
||||
}
|
||||
|
||||
action := "display_" + want
|
||||
if err := notifier.SendDisplayCommand(screen.Slug, action); err != nil {
|
||||
slog.Error("reconciler: send command failed", "screen_id", sc.ScreenID, "action", action, "err", err)
|
||||
slog.Error("reconciler: send command failed", "screen_id", screen.ID, "action", action, "err", err)
|
||||
} else {
|
||||
slog.Info("reconciler: corrected display state", "screen_id", sc.ScreenID, "slug", screen.Slug, "was", got, "want", want)
|
||||
slog.Info("reconciler: corrected display state", "screen_id", screen.ID, "slug", screen.Slug, "was", got, "want", want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue