logo hsb.horse
← 스니펫 목록으로 돌아가기

Snippets

엔티티 내장 쿨다운 경고 억제

반복 경고 억제 로직을 쿼터 엔티티 자체에 내장하는 패턴. 속도 제한 알림이나 과금 경고와 같은 빈번한 경고를 적절히 제어합니다.

게시일: 수정일:

속도 제한이나 쿼터 초과 같은 경고는 짧은 시간에 여러 번 발생하기 쉽습니다. 경고 로직과 쿨다운 상태를 엔티티 자체에 포함시킴으로써 외부 글로벌 관리를 피하면서 적절한 타이밍에만 경고를 발생시킬 수 있습니다.

코드

interface WarnableEntity {
/** 마지막 경고 발생 시각 (밀리초) */
warnedAt: number | null
/** 경고 쿨다운 기간 (밀리초) */
warnCooldown: number
}
/**
* 쿨다운 기반 경고 엔티티의 기본 클래스
*/
class CooldownWarner<T extends WarnableEntity> {
constructor(protected entity: T) {}
/**
* 경고를 발생시켜야 하는지 판단
*/
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
}
/**
* 경고를 발생시키고 warnedAt 업데이트
*/
protected warnBy(message: string): void {
if (!this.shouldWarn()) {
return
}
console.warn(message)
this.entity.warnedAt = Date.now()
}
}
/**
* 속도 제한 엔티티 구현 예제
*/
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(): void {
this.entity.current++
if (this.entity.current >= this.entity.limit) {
this.warnBy(
`Rate limit reached: ${this.entity.current}/${this.entity.limit}`
)
}
}
/**
* 카운터 리셋
*/
reset(): void {
this.entity.current = 0
}
}

사용 예제

// 분당 100개 요청 제한, 경고는 60초에 한 번까지
const limiter = new RateLimiter(100, 60_000)
// 요청 기록
for (let i = 0; i < 150; i++) {
limiter.record()
// 100번째에 경고, 이후 60초간 억제됨
}
// 1분 후 다시 초과하면 경고 재발생
setTimeout(() => {
limiter.record() // 경고가 다시 표시됨
}, 61_000)

작동 원리

  1. 엔티티가 warnedAtwarnCooldown 필드를 가짐
  2. shouldWarn()이 현재 시각과 마지막 경고 시각의 차이를 비교
  3. 쿨다운 기간이 경과했으면 true 반환
  4. warnBy()shouldWarn()을 확인하고 조건 충족 시에만 경고 발생
  5. 경고 후 warnedAt을 업데이트하여 쿨다운 시작

경고 로직과 상태가 엔티티 내부에 완결되어 있어 글로벌 맵이나 셋으로 관리할 필요가 없습니다.

장점

  • 지역성: 경고 상태가 엔티티에 한정되어 외부 관리 불필요
  • 재사용성: 임의의 엔티티에 WarnableEntity를 구현하기만 하면 사용 가능
  • 테스트 용이: 시간을 주입하면 모킹 없이도 테스트 가능
  • 확장 가능: 엔티티마다 독립적인 상태를 가져 병렬 처리에 강함

주의사항

Date.now()에 직접 의존하므로 테스트 시 시간을 주입할 수 있도록 설계를 확장해야 합니다. 또한 엔티티가 영속화되는 경우 warnedAt의 복원과 쿨다운 판정을 적절히 처리해야 합니다.

응용

  • API 속도 제한 경고 알림
  • 과금 시스템의 쿼터 초과 알림
  • 잔액 부족 알림
  • 노이지한 모니터링 조건의 알림 억제
  • 로그 출력의 버스트 방지