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

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

장점

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

주의사항

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

응용

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