レート制限やクォータ超過のような警告は、短時間に何度も発生しやすい。警告ロジックとクールダウン状態をエンティティ自身に持たせることで、外部のグローバル管理を避けつつ、適切なタイミングでだけ警告を発する設計が可能になる。
コード
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)仕組み
- エンティティが
warnedAtとwarnCooldownフィールドを持つ shouldWarn()が現在時刻と最終警告時刻の差分を比較する- クールダウン期間が経過していれば
trueを返す warnBy()がshouldWarn()をチェックし、条件を満たす場合のみ警告を発する- 警告後に
warnedAtを更新してクールダウンを開始する
警告ロジックと状態がエンティティ内に完結しているため、グローバルなマップやセットで管理する必要がない。
メリット
- 局所性:警告の状態がエンティティに閉じており、外部管理が不要
- 再利用性:任意のエンティティに
WarnableEntityを実装するだけで使える - テストしやすい:時刻を注入すればモック不要でテストできる
- スケーラブル:エンティティごとに独立した状態を持つため、並列処理にも強い
注意点
Date.now() に直接依存しているため、テスト時は時刻を注入できるように設計を拡張する必要がある。また、エンティティが永続化される場合、warnedAt の復元とクールダウン判定を適切に扱うこと。
応用
- APIレート制限の警告通知
- 課金システムのクォータ超過アラート
- 残高不足の通知
- ノイジーな監視条件のアラート抑制
- ログ出力のバースト防止
実務メモ
このスニペットは、TypeScript、JavaScript、Design Pattern、Rate Limiting、Monitoring の周辺で同じ操作や判定を毎回書きたくない時に向く。小さな補助として切り出しておくと、呼び出し側では意図だけを追いやすい。
逆に、分岐や前提条件が増えて責務が膨らむなら、1本のスニペットに詰め込まない方がよい。手順と helper を分けるか、役割ごとに切り出す方が保守しやすい。
hsb.horse