logo hsb.horse
← Back to snippets index

Snippets

Entity-Embedded Cooldown Warning Suppression

A pattern that embeds repeated warning suppression logic within the quota entity itself. Properly controls frequent warnings like rate limit notices and billing alerts.

Published: Updated:

Warnings for rate limits and quota violations tend to occur repeatedly in short time spans. By embedding warning logic and cooldown state within the entity itself, you can avoid external global management while ensuring warnings are emitted only at appropriate intervals.

Code

interface WarnableEntity {
/** Timestamp of the last warning (milliseconds) */
warnedAt: number | null
/** Warning cooldown period (milliseconds) */
warnCooldown: number
}
/**
* Base class for entities with cooldown-based warnings
*/
class CooldownWarner<T extends WarnableEntity> {
constructor(protected entity: T) {}
/**
* Determine if a warning should be emitted
*/
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
}
/**
* Emit a warning and update warnedAt
*/
protected warnBy(message: string): void {
if (!this.shouldWarn()) {
return
}
console.warn(message)
this.entity.warnedAt = Date.now()
}
}
/**
* Example implementation: rate limit entity
*/
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
})
}
/**
* Record a request and warn if necessary
*/
record(): void {
this.entity.current++
if (this.entity.current >= this.entity.limit) {
this.warnBy(
`Rate limit reached: ${this.entity.current}/${this.entity.limit}`
)
}
}
/**
* Reset the counter
*/
reset(): void {
this.entity.current = 0
}
}

Usage

// 100 requests/min rate limit, warn at most once per 60 seconds
const limiter = new RateLimiter(100, 60_000)
// Record requests
for (let i = 0; i < 150; i++) {
limiter.record()
// Warns at the 100th request, suppressed for 60s after that
}
// After 1 minute, exceeding again will trigger another warning
setTimeout(() => {
limiter.record() // Warning is displayed again
}, 61_000)

How It Works

  1. The entity has warnedAt and warnCooldown fields
  2. shouldWarn() compares the current time with the last warning timestamp
  3. Returns true if the cooldown period has elapsed
  4. warnBy() checks shouldWarn() and emits a warning only if the condition is met
  5. After warning, updates warnedAt to start the cooldown

Since the warning logic and state are encapsulated within the entity, there’s no need for global maps or sets.

Benefits

  • Locality: Warning state is self-contained within the entity, no external management needed
  • Reusability: Any entity can implement WarnableEntity to use this pattern
  • Testable: Inject time for testing without mocks
  • Scalable: Each entity maintains independent state, friendly to concurrent processing

Caveats

Direct dependency on Date.now() means you’ll need to extend the design to inject time for testing. Also, if entities are persisted, ensure proper restoration of warnedAt and cooldown logic.

Applications

  • Warning notifications for API rate limits
  • Quota violation alerts in billing systems
  • Low-balance notifications
  • Suppression of noisy monitoring alerts
  • Burst prevention in logging