Files
talk/internal/queue/rate.go
T

57 lines
1.7 KiB
Go
Raw Normal View History

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)
}