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秒に1回まで
const limiter = new RateLimiter(100, 60_000)
// リクエストを記録
for (let i = 0; i < 150; i++) {
limiter.record()
// 100回目で警告、101回目以降は60秒間抑制される
}
// 1分後に再度超過すると、また警告が発される
setTimeout(() => {
limiter.record() // 警告が再度表示される
}, 61_000)

仕組み

  1. エンティティが warnedAtwarnCooldown フィールドを持つ
  2. shouldWarn() が現在時刻と最終警告時刻の差分を比較する
  3. クールダウン期間が経過していれば true を返す
  4. warnBy()shouldWarn() をチェックし、条件を満たす場合のみ警告を発する
  5. 警告後に warnedAt を更新してクールダウンを開始する

警告ロジックと状態がエンティティ内に完結しているため、グローバルなマップやセットで管理する必要がない。

メリット

  • 局所性:警告の状態がエンティティに閉じており、外部管理が不要
  • 再利用性:任意のエンティティに WarnableEntity を実装するだけで使える
  • テストしやすい:時刻を注入すればモック不要でテストできる
  • スケーラブル:エンティティごとに独立した状態を持つため、並列処理にも強い

注意点

Date.now() に直接依存しているため、テスト時は時刻を注入できるように設計を拡張する必要がある。また、エンティティが永続化される場合、warnedAt の復元とクールダウン判定を適切に扱うこと。

応用

  • APIレート制限の警告通知
  • 課金システムのクォータ超過アラート
  • 残高不足の通知
  • ノイジーな監視条件のアラート抑制
  • ログ出力のバースト防止

実務メモ

このスニペットは、TypeScript、JavaScript、Design Pattern、Rate Limiting、Monitoring の周辺で同じ操作や判定を毎回書きたくない時に向く。小さな補助として切り出しておくと、呼び出し側では意図だけを追いやすい。

逆に、分岐や前提条件が増えて責務が膨らむなら、1本のスニペットに詰め込まない方がよい。手順と helper を分けるか、役割ごとに切り出す方が保守しやすい。