局所トレーサビリティ — グループ: LIMIT

# 局所トレーサビリティビュー グループ: LIMIT

生成日時: 2026-03-11 00:06:09

### 対象アイテム

5

### REQ

1

### ARCH

1

### SPEC

1

### TST

1

### IMPL

1

### レビュー済

5/5

### Suspect

0

### グループ

LIMIT

## トレーサビリティマトリクス

✓=レビュー済 ○=未レビュー ⚠=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% | —

## アイテム詳細

### REQ008 REQ {h(g)} ✓ レビュー済

関数の実行頻度をトークンバケット方式で制限し、外部APIの呼び出しレートを制御できること。同期・非同期の両方に対応すること。

関数の実行頻度をトークンバケット方式で制限し、外部APIの呼び出しレートを制御できること。同期・非同期の両方に対応すること。

親: —

子: ARCH008

### ARCH008 ARCH {h(g)} ✓ レビュー済

## コンポーネント構成

    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` により、マルチスレッド環境での二重消費を防止

## コンポーネント構成 ```mermaid 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` | ## データフロー ```mermaid 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

### SPEC018 SPEC {h(g)} ✓ レビュー済

## インターフェース

    class TokenBucket(LimiterProtocol):
        def consume(self, cost: float = 1.0) -> None: ...
        async def consume_async(self, cost: float = 1.0) -> None: ...

## 振る舞い

### GCRAアルゴリズム

- 各リクエストに対して「次回実行可能な理論時刻 (TAT: Theoretical Arrival Time)」を計算・更新する。
- 現在時刻が `TAT - 許容バースト` 以前の場合、リクエストを拒否または待機させる。

### 同期 vs 非同期

- `consume`: 待機が必要な場合は `time.sleep()` でブロック。
- `consume_async`: 待機が必要な場合は `asyncio.sleep()` で非占有待機。

## パラメータ詳細

設定 | デフォルト | 説明
--- | --- | ---
`tokens_per_minute` | 必須 | 1分間に許可する平均リクエスト数（コスト合計）
`max_burst` | `1.0` | 許容されるバースト数（トークン単位）

## エラーハンドリング

- 即時拒否モード: 待機を許容しない設定でレート超過した場合、`RateLimitError` (ValueErrorのサブクラス) を送出する。

## エッジケース

- 高コストリクエスト: `max_burst` を超えるコストを持つ単一リクエストは、常に拒否される。
- アイドル時間: 長時間リクエストがない場合も、`TAT` は現在時刻より過去に一定以上離れないよう補正される（過度なバーストの防止）。

## インターフェース ```python class TokenBucket(LimiterProtocol): def consume(self, cost: float = 1.0) -> None: ... async def consume_async(self, cost: float = 1.0) -> None: ... ``` ## 振る舞い ### GCRAアルゴリズム - 各リクエストに対して「次回実行可能な理論時刻 (TAT: Theoretical Arrival Time)」を計算・更新する。 - 現在時刻が `TAT - 許容バースト` 以前の場合、リクエストを拒否または待機させる。 ### 同期 vs 非同期 - `consume`: 待機が必要な場合は `time.sleep()` でブロック。 - `consume_async`: 待機が必要な場合は `asyncio.sleep()` で非占有待機。 ## パラメータ詳細 | 設定 | デフォルト | 説明 | |---|---|---| | `tokens_per_minute` | 必須 | 1分間に許可する平均リクエスト数（コスト合計） | | `max_burst` | `1.0` | 許容されるバースト数（トークン単位） | ## エラーハンドリング - **即時拒否モード**: 待機を許容しない設定でレート超過した場合、`RateLimitError` (ValueErrorのサブクラス) を送出する。 ## エッジケース - **高コストリクエスト**: `max_burst` を超えるコストを持つ単一リクエストは、常に拒否される。 - **アイドル時間**: 長時間リクエストがない場合も、`TAT` は現在時刻より過去に一定以上離れないよう補正される（過度なバーストの防止）。

親: ARCH008

子: IMPL018, TST018

### TST018 TST {h(g)} ✓ レビュー済

## 目的

`TokenBucket` はAPI呼び出しやリソースアクセスのレート制限を実現する。レートリミッターの不具合はAPIの過負荷（制限が甘い場合）やスループットの不必要な低下（制限が厳しすぎる場合）を招く。GCRA アルゴリズムのスムーズなレート制御を検証する。

## 検証観点

- 初期化バリデーション: rate ≤ 0 や capacity ≤ 0 などの不正パラメータが拒否されること
- max_cost 超過拒否: 1回のリクエストコストがバケット容量を超える場合に即座に拒否されること（無限待機にならないこと）
- GCRA 待機動作: バケットが空の状態でリクエストした場合に、トークン補充まで適切な時間だけ待機すること。待機時間がレートに基づいて正確であること
- バースト許容: 容量分のリクエストがバーストで処理でき、超過分からスロットリングが開始されること

## 目的 `TokenBucket` はAPI呼び出しやリソースアクセスのレート制限を実現する。レートリミッターの不具合はAPIの過負荷（制限が甘い場合）やスループットの不必要な低下（制限が厳しすぎる場合）を招く。GCRA アルゴリズムのスムーズなレート制御を検証する。 ## 検証観点 - **初期化バリデーション**: rate ≤ 0 や capacity ≤ 0 などの不正パラメータが拒否されること - **max_cost 超過拒否**: 1回のリクエストコストがバケット容量を超える場合に即座に拒否されること（無限待機にならないこと） - **GCRA 待機動作**: バケットが空の状態でリクエストした場合に、トークン補充まで適切な時間だけ待機すること。待機時間がレートに基づいて正確であること - **バースト許容**: 容量分のリクエストがバーストで処理でき、超過分からスロットリングが開始されること

references: tests/unit/test_limiter.py

親: SPEC018

子: —

### IMPL018 IMPL {h(g)} ✓ レビュー済

## 実装概要

`LimiterProtocol` を実装する `TokenBucket` クラス。 GCRA (Generic Cell Rate Algorithm) に基づき、スレッドセーフおよび 非同期対応のスムーズなレートリミッタを提供する。 内部状態として Theoretical Arrival Time (TAT) を保持し、 `consume()` で同期的スリープ、`consume_async()` で非同期的スリープを行う。

## 設計判断

### GCRAアルゴリズムの採用

伝統的なトークンバケットとは異なり、長時間アイドル後に 一気にバーストを許容しない「Strict Pacing」を実現できる。 TATの更新と現在時刻の比較だけで待機時間を計算できるため、 メモリ効率と計算効率に優れる。

### モノトニッククロックの利用

時刻の取得に `time.monotonic()` を使用し、システム時刻の変更（NTP同期など）の 影響を受けない堅牢な設計としている。

## 実装メモ

- `_consume_reservation()` メソッドが待機時間の計算と TAT 更新を `threading.Lock` でアトミックに行う
- `cost > max_cost`（バケット容量超過）の場合は、どれだけ待っても 処理できないため即座に `ValueError` を送出する
- 同期パスは `time.sleep()`、非同期パスは `asyncio.sleep()` で待機する

## 実装概要 `LimiterProtocol` を実装する `TokenBucket` クラス。 GCRA (Generic Cell Rate Algorithm) に基づき、スレッドセーフおよび 非同期対応のスムーズなレートリミッタを提供する。 内部状態として Theoretical Arrival Time (TAT) を保持し、 `consume()` で同期的スリープ、`consume_async()` で非同期的スリープを行う。 ## 設計判断 ### GCRAアルゴリズムの採用 伝統的なトークンバケットとは異なり、長時間アイドル後に 一気にバーストを許容しない「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

子: —