package queue import ( "sync" "time" ) // RateLimiter ist die Struktur für das Daemon-Gesetz gegen Ansage-Spam // (Spec: Default ca. 1 Ansage / 30 s, konfigurierbar). // // SEAM FÜR TASK 05: Struktur und Semantik stehen und sind getestet, sind // aber noch NICHT an den Worker-Loop angebunden — Task 04 erzeugt keinen // Limiter (unbegrenzt, so verlangt es der Task-04-Brief: „Default unendlich // in T04-Tests, dokumentiert"). Task 05 verdrahtet den Limiter (config // queue.rate_limit) in den Loop und ergänzt die prioritätsbewusste // Entscheidung: low verwerfen, normal parken, high konfigurierbar verstoßen // (queue.allow_high_burst) — dafür ist Next() bereits Teil der Struktur. type RateLimiter struct { // Interval ist der Mindestabstand zwischen zwei Ansage-Starts. // 0 oder negativ = unbegrenzt (Task-04-Default). Interval time.Duration mu sync.Mutex last time.Time // Start der zuletzt per Reserve gebuchten Ansage } // Allow meldet, ob sofort eine Ansage starten dürfte. func (l *RateLimiter) Allow() bool { if l == nil || l.Interval <= 0 { return true } l.mu.Lock() defer l.mu.Unlock() return time.Since(l.last) >= l.Interval } // Reserve bucht einen Ansage-Slot (direkt nach Allow aufrufen). func (l *RateLimiter) Reserve() { if l == nil || l.Interval <= 0 { return } l.mu.Lock() defer l.mu.Unlock() l.last = time.Now() } // Next liefert, wann der nächste Ansage-Slot frei wird (Nullzeit, wenn // Allow sofort true liefern würde) — Basis für das Parken wartender Items // in Task 05. func (l *RateLimiter) Next() time.Time { if l == nil || l.Interval <= 0 { return time.Time{} } l.mu.Lock() defer l.mu.Unlock() return l.last.Add(l.Interval) }