- Server no longer mirrors app.Runtime services (gov/svc/pwSvc/...): 574 call sites now use accessors in runtime_accessors.go - backgroundLoop (mutex+sync.Once) stops sweeper/publisher/reminder/wsGC goroutines race-free (baseline44161d2areproduced DATA RACE; now green under -race) - goose 00071 duplicate (dialogue merge1da17a28brought two 00071): context-conflict-adjudications renumbered to 00072; dev DB applied only through 00070 so zero data migration - task_finalize tests build minimal app.Runtime; test injection via serverTestOverrides + setOverride* (explicit-nil markers for fail-closed cases)
47 lines
949 B
Go
47 lines
949 B
Go
package server
|
|
|
|
import (
|
|
"context"
|
|
"log/slog"
|
|
"time"
|
|
)
|
|
|
|
const defaultReminderPollInterval = 15 * time.Minute
|
|
|
|
func (s *Server) startNotificationReminderLoop() {
|
|
if s == nil || s.notifySvc() == nil || !s.notifySvc().Available() {
|
|
return
|
|
}
|
|
stopCh, ok := s.reminderLoop.start()
|
|
if !ok {
|
|
return
|
|
}
|
|
go func() {
|
|
ticker := time.NewTicker(defaultReminderPollInterval)
|
|
defer ticker.Stop()
|
|
s.runStageAdvanceReminders(context.Background())
|
|
for {
|
|
select {
|
|
case <-stopCh:
|
|
return
|
|
case <-ticker.C:
|
|
s.runStageAdvanceReminders(context.Background())
|
|
}
|
|
}
|
|
}()
|
|
}
|
|
|
|
func (s *Server) runStageAdvanceReminders(ctx context.Context) {
|
|
if s.notifySvc() == nil || !s.notifySvc().Available() {
|
|
return
|
|
}
|
|
n, err := s.notifySvc().ProcessStageAdvanceReminders(ctx)
|
|
if err != nil {
|
|
slog.Warn("stage advance reminder scan failed", "error", err)
|
|
return
|
|
}
|
|
if n > 0 {
|
|
slog.Info("stage advance 24h reminders sent", "count", n)
|
|
}
|
|
}
|