Warnungen für Ratenlimits und Quota-Überschreitungen treten häufig in kurzen Zeitspannen wiederholt auf. Durch Einbetten der Warnlogik und des Cooldown-Status in die Entität selbst können Sie eine externe globale Verwaltung vermeiden und gleichzeitig sicherstellen, dass Warnungen nur in angemessenen Intervallen ausgegeben werden.
Code
interface WarnableEntity { /** Zeitstempel der letzten Warnung (Millisekunden) */ warnedAt: number | null /** Cooldown-Zeitraum für Warnungen (Millisekunden) */ warnCooldown: number}
/** * Basisklasse für Entitäten mit Cooldown-basierten Warnungen */class CooldownWarner<T extends WarnableEntity> { constructor(protected entity: T) {}
/** * Ermittelt, ob eine Warnung ausgegeben werden soll */ protected shouldWarn(): boolean { const now = Date.now() if (this.entity.warnedAt === null) { return true } const elapsed = now - this.entity.warnedAt return elapsed >= this.entity.warnCooldown }
/** * Gibt eine Warnung aus und aktualisiert warnedAt */ protected warnBy(message: string): void { if (!this.shouldWarn()) { return } console.warn(message) this.entity.warnedAt = Date.now() }}
/** * Beispielimplementierung: Ratenlimit-Entität */interface RateLimitEntity extends WarnableEntity { limit: number current: number}
class RateLimiter extends CooldownWarner<RateLimitEntity> { constructor(limit: number, cooldown: number = 60_000) { super({ limit, current: 0, warnedAt: null, warnCooldown: cooldown }) }
/** * Zeichnet eine Anfrage auf und warnt bei Bedarf */ record(): void { this.entity.current++
if (this.entity.current >= this.entity.limit) { this.warnBy( `Rate limit reached: ${this.entity.current}/${this.entity.limit}` ) } }
/** * Setzt den Zähler zurück */ reset(): void { this.entity.current = 0 }}Verwendung
// 100 Anfragen/Min Ratenlimit, höchstens einmal alle 60 Sekunden warnenconst limiter = new RateLimiter(100, 60_000)
// Anfragen aufzeichnenfor (let i = 0; i < 150; i++) { limiter.record() // Warnt bei der 100. Anfrage, danach 60s lang unterdrückt}
// Nach 1 Minute löst erneutes Überschreiten eine weitere Warnung aussetTimeout(() => { limiter.record() // Warnung wird erneut angezeigt}, 61_000)Funktionsweise
- Die Entität verfügt über die Felder
warnedAtundwarnCooldown shouldWarn()vergleicht die aktuelle Zeit mit dem letzten Warnungszeitstempel- Gibt
truezurück, wenn die Cooldown-Periode abgelaufen ist warnBy()prüftshouldWarn()und gibt eine Warnung nur aus, wenn die Bedingung erfüllt ist- Nach der Warnung aktualisiert es
warnedAt, um den Cooldown zu starten
Da die Warnlogik und der Status in der Entität gekapselt sind, sind keine globalen Maps oder Sets erforderlich.
Vorteile
- Lokalität: Der Warnungsstatus ist in der Entität enthalten, keine externe Verwaltung erforderlich
- Wiederverwendbarkeit: Jede Entität kann
WarnableEntityimplementieren, um dieses Muster zu verwenden - Testbar: Injizieren Sie Zeit zum Testen ohne Mocks
- Skalierbar: Jede Entität pflegt einen unabhängigen Status, freundlich zur nebenläufigen Verarbeitung
Vorsichtsmaßnahmen
Die direkte Abhängigkeit von Date.now() bedeutet, dass Sie das Design erweitern müssen, um Zeit für Tests zu injizieren. Wenn Entitäten persistiert werden, stellen Sie außerdem die ordnungsgemäße Wiederherstellung von warnedAt und die Cooldown-Logik sicher.
Anwendungen
- Warnungsbenachrichtigungen für API-Ratenlimits
- Quota-Überschreitungswarnungen in Abrechnungssystemen
- Benachrichtigungen bei niedrigem Guthaben
- Unterdrückung lauter Überwachungswarnungen
- Burst-Verhinderung bei der Protokollierung
hsb.horse