Les avertissements de limitation de débit et de dépassement de quota ont tendance à se produire de manière répétée sur de courtes périodes. En intégrant la logique d’avertissement et l’état de cooldown dans l’entité elle-même, vous pouvez éviter la gestion globale externe tout en garantissant que les avertissements ne sont émis qu’aux intervalles appropriés.
Code
interface WarnableEntity { /** Horodatage du dernier avertissement (millisecondes) */ warnedAt: number | null /** Période de cooldown des avertissements (millisecondes) */ warnCooldown: number}
/** * Classe de base pour les entités avec avertissements basés sur le cooldown */class CooldownWarner<T extends WarnableEntity> { constructor(protected entity: T) {}
/** * Détermine si un avertissement doit être émis */ 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 }
/** * Émet un avertissement et met à jour warnedAt */ protected warnBy(message: string): void { if (!this.shouldWarn()) { return } console.warn(message) this.entity.warnedAt = Date.now() }}
/** * Exemple d'implémentation : entité de limitation de débit */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 }) }
/** * Enregistre une requête et avertit si nécessaire */ record(): void { this.entity.current++
if (this.entity.current >= this.entity.limit) { this.warnBy( `Rate limit reached: ${this.entity.current}/${this.entity.limit}` ) } }
/** * Réinitialise le compteur */ reset(): void { this.entity.current = 0 }}Utilisation
// Limitation de 100 requêtes/min, avertir au maximum une fois toutes les 60 secondesconst limiter = new RateLimiter(100, 60_000)
// Enregistrer des requêtesfor (let i = 0; i < 150; i++) { limiter.record() // Avertit à la 100e requête, supprimé pendant 60s après}
// Après 1 minute, dépasser à nouveau déclenchera un autre avertissementsetTimeout(() => { limiter.record() // L'avertissement s'affiche à nouveau}, 61_000)Comment ça fonctionne
- L’entité possède les champs
warnedAtetwarnCooldown shouldWarn()compare l’heure actuelle avec l’horodatage du dernier avertissement- Retourne
truesi la période de cooldown s’est écoulée warnBy()vérifieshouldWarn()et émet un avertissement uniquement si la condition est remplie- Après l’avertissement, met à jour
warnedAtpour démarrer le cooldown
La logique d’avertissement et l’état étant encapsulés dans l’entité, il n’y a pas besoin de maps ou de sets globaux.
Avantages
- Localité : L’état d’avertissement est autonome dans l’entité, aucune gestion externe nécessaire
- Réutilisabilité : N’importe quelle entité peut implémenter
WarnableEntitypour utiliser ce motif - Testable : Injectez le temps pour tester sans mocks
- Évolutif : Chaque entité maintient un état indépendant, favorable au traitement concurrent
Mises en garde
La dépendance directe à Date.now() signifie que vous devrez étendre la conception pour injecter le temps lors des tests. De plus, si les entités sont persistées, assurez-vous de restaurer correctement warnedAt et la logique de cooldown.
Applications
- Notifications d’avertissement pour les limites de débit d’API
- Alertes de dépassement de quota dans les systèmes de facturation
- Notifications de solde faible
- Suppression des alertes de surveillance bruyantes
- Prévention des rafales dans les journaux
hsb.horse