✓=レビュー済 ○=未レビュー ⚠=Suspect(複数同時表示あり。IDクリックで詳細へ)
| グループ | REQ | ARCH | SPEC | TST | IMPL |
|---|---|---|---|---|---|
| LIMIT | REQ008 ✓ 関数の実行頻度をトークンバケット方式で制限し、外部APIの呼び出しレートを制御できること。同期・非同期の両方に対応すること。 | ARCH008 ✓ ## コンポーネント構成 ```mermaid graph TD A["@spot.consume"] -->|宣言的適用| B[LimiterProto... | SPEC018 ✓ ## インターフェース ```python class TokenBucket(LimiterProtocol): def consume(self,... | TST018 ✓ ## 目的 `TokenBucket` はAPI呼び出しやリソースアクセスのレート制限を実現する。レートリミッターの不具合はAPIの過負荷(制限が甘い場合)や... | IMPL018 ✓ ## 実装概要 `LimiterProtocol` を実装する `TokenBucket` クラス。 GCRA (Generic Cell Rate Algo... |
| リンク方向 | カバー数 | カバー率 | 未カバー |
|---|---|---|---|
| ARCH → REQ | 1 / 1 | 100.0% | — |
| SPEC → ARCH | 1 / 1 | 100.0% | — |
| TST → SPEC | 1 / 1 | 100.0% | — |
| IMPL → SPEC | 1 / 1 | 100.0% | — |
関数の実行頻度をトークンバケット方式で制限し、外部APIの呼び出しレートを制御できること。同期・非同期の両方に対応すること。
親: —
子: ARCH008
graph TD
A["@spot.consume"] -->|宣言的適用| B[LimiterProtocol]
C[core.Spot] -->|DI| B
D[TokenBucket] --> B
D -->|アルゴリズム| E[GCRA]
D -->|時刻同期| F[monotonic clock]
| コンポーネント | 責務 | インターフェース |
|---|---|---|
| TokenBucket | GCRAアルゴリズムによるスムースなトラフィック制御 | consume(), consume_async() |
| @spot.consume | 関数実行前のトークン消費を透過的に行うデコレータ | cost (int or callable) |
| LimiterProtocol | レートリミッターの差し替えを可能にするインターフェース | LimiterProtocol |
sequenceDiagram
participant User as ユーザーコード
participant Dec as @spot.consume
participant Bucket as TokenBucket
User->>Dec: call func()
Dec->>Bucket: consume(cost)
Bucket->>Bucket: 次回実行許可時刻の計算 (GCRA)
alt 許可
Bucket-->>Dec: OK
Dec->>User: execute func()
else 拒否 (Over rate)
Bucket-->>Dec: raise ValueError/RateLimitError
end
| 技術領域 | 選定 | 理由 |
|---|---|---|
| アルゴリズム | GCRA (Generic Cell Rate Algorithm) | 固定ウィンドウと違い「スムースな」流量制御が可能 |
| 待機制御 | asyncio.sleep / time.sleep | 同期・非同期の両方のコンテキストで正確なスロットリングを実現 |
| コスト計算 | ダイナミックコスト | 引数に応じて消費トークン数を動的に変更可能 |
正確性: time.monotonic() を使用し、システム時刻の変更(NTP同期等)の影響を受けない
バースト制御: max_burst 設定により、アイドル後の過度なバーストを防止
スレッド安全: threading.Lock により、マルチスレッド環境での二重消費を防止
親: REQ008
子: SPEC018
class TokenBucket(LimiterProtocol):
def consume(self, cost: float = 1.0) -> None: ...
async def consume_async(self, cost: float = 1.0) -> None: ...
TAT - 許容バースト 以前の場合、リクエストを拒否または待機させる。consume: 待機が必要な場合は time.sleep() でブロック。consume_async: 待機が必要な場合は asyncio.sleep() で非占有待機。| 設定 | デフォルト | 説明 |
|---|---|---|
tokens_per_minute |
必須 | 1分間に許可する平均リクエスト数(コスト合計) |
max_burst |
1.0 |
許容されるバースト数(トークン単位) |
RateLimitError (ValueErrorのサブクラス) を送出する。max_burst を超えるコストを持つ単一リクエストは、常に拒否される。TAT は現在時刻より過去に一定以上離れないよう補正される(過度なバーストの防止)。親: ARCH008
TokenBucket はAPI呼び出しやリソースアクセスのレート制限を実現する。レートリミッターの不具合はAPIの過負荷(制限が甘い場合)やスループットの不必要な低下(制限が厳しすぎる場合)を招く。GCRA アルゴリズムのスムーズなレート制御を検証する。
親: SPEC018
子: —
LimiterProtocol を実装する TokenBucket クラス。
GCRA (Generic Cell Rate Algorithm) に基づき、スレッドセーフおよび
非同期対応のスムーズなレートリミッタを提供する。
内部状態として Theoretical Arrival Time (TAT) を保持し、
consume() で同期的スリープ、consume_async() で非同期的スリープを行う。
伝統的なトークンバケットとは異なり、長時間アイドル後に 一気にバーストを許容しない「Strict Pacing」を実現できる。 TATの更新と現在時刻の比較だけで待機時間を計算できるため、 メモリ効率と計算効率に優れる。
時刻の取得に time.monotonic() を使用し、システム時刻の変更(NTP同期など)の
影響を受けない堅牢な設計としている。
_consume_reservation() メソッドが待機時間の計算と TAT 更新を
threading.Lock でアトミックに行うcost > max_cost(バケット容量超過)の場合は、どれだけ待っても
処理できないため即座に ValueError を送出するtime.sleep()、非同期パスは asyncio.sleep() で待機するreferences: src/beautyspot/limiter.py
親: SPEC018
子: —