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

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

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

### 対象アイテム

5

### REQ

1

### ARCH

1

### SPEC

1

### TST

1

### IMPL

1

### レビュー済

5/5

### Suspect

0

### グループ

MAINT

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

✓=レビュー済 ○=未レビュー ⚠=Suspect（複数同時表示あり。IDクリックで詳細へ）

グループ | REQ | ARCH | SPEC | TST | IMPL
--- | --- | --- | --- | --- | ---
MAINT | REQ010 ✓ 期限切れキャッシュの削除、孤立Blobファイルのガベージコレクション、時間ベースの一括削除（prune）等のメンテナンス操作ができること。 | ARCH010 ✓ ## コンポーネント構成 ```mermaid graph TD A[MaintenanceService] -->|操作集約| B[TaskDBBase... | SPEC020 ✓ ## インターフェース ```python class MaintenanceService: def clean_garbage(self, gra... | TST020 ✓ ## 目的 `MaintenanceService` は CLI やダッシュボードからのシステム管理操作を仲介するサービス層である。タスク詳細の表示ミスは運用... | IMPL020 ✓ ## 実装概要 `MaintenanceService` クラスがDBとBlobストレージ間の整合性チェック、 期限切れキャッシュの削除、孤立ファイルの検出と...

## カバレッジ（局所）

リンク方向 | カバー数 | カバー率 | 未カバー
--- | --- | --- | ---
ARCH → REQ | 1 / 1 | 100.0% | —
SPEC → ARCH | 1 / 1 | 100.0% | —
TST → SPEC | 1 / 1 | 100.0% | —
IMPL → SPEC | 1 / 1 | 100.0% | —

## アイテム詳細

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

期限切れキャッシュの削除、孤立Blobファイルのガベージコレクション、時間ベースの一括削除（prune）等のメンテナンス操作ができること。

期限切れキャッシュの削除、孤立Blobファイルのガベージコレクション、時間ベースの一括削除（prune）等のメンテナンス操作ができること。

親: —

子: ARCH010

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

## コンポーネント構成

    graph TD
      A[MaintenanceService] -->|操作集約| B[TaskDBBase]
      A -->|操作集約| C[BlobStorageBase]
      A -->|自動実行| D[Probabilistic Eviction]

## コンポーネント責務

コンポーネント | 責務 | インターフェース
--- | --- | ---
MaintenanceService | DBとストレージを跨ぐクリーンアップ操作のファサード | `clean_garbage()`, `prune()`
TaskDBBase | 参照カウントや期限切れレコードの提供 | `get_blob_refs()`, `delete_expired()`
BlobStorageBase | 物理ファイルの列挙と削除 | `list_keys()`, `delete()`

## データフロー (GCプロセス)

    sequenceDiagram
      participant Service as MaintenanceService
      participant DB as TaskDB
      participant Storage as BlobStorage

      Service->>DB: get_blob_refs()
      DB-->>Service: 有効な参照リスト (Whitelist)
      Service->>Storage: list_keys()
      Storage-->>Service: 全ファイルリスト
      Service->>Service: 差分抽出 (孤立ファイルの特定)
      Service->>Storage: delete(orphan_keys)
      Note over Service: 猶予期間 (grace_period) を考慮して削除

## 技術選定

技術領域 | 選定 | 理由
--- | --- | ---
削除ポリシー | ホワイトリスト方式 | DBに記録がないBlobを削除対象とすることで、データの整合性を担保
競合防止 | 更新時刻確認 (mtime) | 保存中のファイルを誤って消さないよう、一定時間経過した孤立のみ削除
実行頻度 | 確率的オートエビクション | 書き込み時に低確率でGCをキックし、手動メンテなしでの健康度を維持

## 非機能要件方針

- 安全性: DBレコードの削除 → Blobの削除の順序を徹底し、参照エラーを防止
- 可用性: メンテナンス中も通常のキャッシュ読み取りを妨げないロック粒度
- 観測性: 削除されたタスク数や解放された容量を統計として返却

## コンポーネント構成 ```mermaid graph TD A[MaintenanceService] -->|操作集約| B[TaskDBBase] A -->|操作集約| C[BlobStorageBase] A -->|自動実行| D[Probabilistic Eviction] ``` ## コンポーネント責務 | コンポーネント | 責務 | インターフェース | |---|---|---| | MaintenanceService | DBとストレージを跨ぐクリーンアップ操作のファサード | `clean_garbage()`, `prune()` | | TaskDBBase | 参照カウントや期限切れレコードの提供 | `get_blob_refs()`, `delete_expired()` | | BlobStorageBase | 物理ファイルの列挙と削除 | `list_keys()`, `delete()` | ## データフロー (GCプロセス) ```mermaid sequenceDiagram participant Service as MaintenanceService participant DB as TaskDB participant Storage as BlobStorage Service->>DB: get_blob_refs() DB-->>Service: 有効な参照リスト (Whitelist) Service->>Storage: list_keys() Storage-->>Service: 全ファイルリスト Service->>Service: 差分抽出 (孤立ファイルの特定) Service->>Storage: delete(orphan_keys) Note over Service: 猶予期間 (grace_period) を考慮して削除 ``` ## 技術選定 | 技術領域 | 選定 | 理由 | |---|---|---| | 削除ポリシー | ホワイトリスト方式 | DBに記録がないBlobを削除対象とすることで、データの整合性を担保 | | 競合防止 | 更新時刻確認 (mtime) | 保存中のファイルを誤って消さないよう、一定時間経過した孤立のみ削除 | | 実行頻度 | 確率的オートエビクション | 書き込み時に低確率でGCをキックし、手動メンテなしでの健康度を維持 | ## 非機能要件方針 - **安全性**: DBレコードの削除 → Blobの削除の順序を徹底し、参照エラーを防止 - **可用性**: メンテナンス中も通常のキャッシュ読み取りを妨げないロック粒度 - **観測性**: 削除されたタスク数や解放された容量を統計として返却

親: REQ010

子: SPEC020

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

## インターフェース

    class MaintenanceService:
        def clean_garbage(self, grace_period: int = 3600) -> GarbageStats: ...
        def prune(self, days: int, func_name: str | None = None) -> int: ...
        def clear(self, func_name: str | None = None) -> int: ...

## 振る舞い

### ガベージコレクション (`clean_garbage`)

1. DB Flush: 保存中のタスクをDBへ反映させる
2. 期限切れ削除: `delete_expired()` でDBから古いタスクを除去
3. 孤立Blobスキャン: DB内の全 `blob_key` とストレージ内の全ファイルを比較
4. 物理削除: 参照のないBlobのうち、作成から `grace_period` 以上経過したものを削除
5. 構造清掃: ストレージ内の空ディレクトリを削除

## パラメータ詳細

パラメータ | デフォルト | 説明
--- | --- | ---
`grace_period` | `3600` | 孤立Blobを削除するまでの猶予期間（秒）。並行実行中の保存を保護する
`days` | なし | `prune` で削除対象とする経過日数

## エラーハンドリング

- 削除失敗: 個別のファイル削除失敗は警告ログに留め、全体の処理は継続する。
- DBロック: メンテナンス中にDBがロックされた場合は、タイムアウトまで待機し失敗させる。

## エッジケース

- 大規模ストレージ: Blobの列挙はジェネレータで行い、メモリ使用量を抑制する。
- 名前空間: `clear(func_name)` は前方一致ではなく、完全一致（または glob）で判定する。

## インターフェース ```python class MaintenanceService: def clean_garbage(self, grace_period: int = 3600) -> GarbageStats: ... def prune(self, days: int, func_name: str | None = None) -> int: ... def clear(self, func_name: str | None = None) -> int: ... ``` ## 振る舞い ### ガベージコレクション (`clean_garbage`) 1. **DB Flush**: 保存中のタスクをDBへ反映させる 2. **期限切れ削除**: `delete_expired()` でDBから古いタスクを除去 3. **孤立Blobスキャン**: DB内の全 `blob_key` とストレージ内の全ファイルを比較 4. **物理削除**: 参照のないBlobのうち、作成から `grace_period` 以上経過したものを削除 5. **構造清掃**: ストレージ内の空ディレクトリを削除 ## パラメータ詳細 | パラメータ | デフォルト | 説明 | |---|---|---| | `grace_period` | `3600` | 孤立Blobを削除するまでの猶予期間（秒）。並行実行中の保存を保護する | | `days` | なし | `prune` で削除対象とする経過日数 | ## エラーハンドリング - **削除失敗**: 個別のファイル削除失敗は警告ログに留め、全体の処理は継続する。 - **DBロック**: メンテナンス中にDBがロックされた場合は、タイムアウトまで待機し失敗させる。 ## エッジケース - **大規模ストレージ**: Blobの列挙はジェネレータで行い、メモリ使用量を抑制する。 - **名前空間**: `clear(func_name)` は前方一致ではなく、完全一致（または glob）で判定する。

親: ARCH010

子: IMPL020, TST020

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

## 目的

`MaintenanceService` は CLI やダッシュボードからのシステム管理操作を仲介するサービス層である。タスク詳細の表示ミスは運用者の誤判断を招き、メンテナンス操作の不備はデータの意図しない削除に繋がる。

## 検証観点

- タスク詳細取得: 存在するタスクIDに対して正しいメタデータ（func_name, input_key, result, created_at 等）が返却されること
- 存在しないタスク: 不在のタスクIDに対して `None` が返却され、例外が送出されないこと
- 統計情報: キャッシュの件数、サイズ、関数ごとの分布など統計情報が正確に算出されること
- クリア操作: 指定条件に合致するタスクのみが削除され、他のタスクが影響を受けないこと
- GC 操作: 有効期限切れタスクの削除と孤立Blobファイルのクリーンアップが正しく連動すること

## 目的 `MaintenanceService` は CLI やダッシュボードからのシステム管理操作を仲介するサービス層である。タスク詳細の表示ミスは運用者の誤判断を招き、メンテナンス操作の不備はデータの意図しない削除に繋がる。 ## 検証観点 - **タスク詳細取得**: 存在するタスクIDに対して正しいメタデータ（func_name, input_key, result, created_at 等）が返却されること - **存在しないタスク**: 不在のタスクIDに対して `None` が返却され、例外が送出されないこと - **統計情報**: キャッシュの件数、サイズ、関数ごとの分布など統計情報が正確に算出されること - **クリア操作**: 指定条件に合致するタスクのみが削除され、他のタスクが影響を受けないこと - **GC 操作**: 有効期限切れタスクの削除と孤立Blobファイルのクリーンアップが正しく連動すること

references: tests/unit/test_maintenance.py

親: SPEC020

子: —

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

## 実装概要

`MaintenanceService` クラスがDBとBlobストレージ間の整合性チェック、 期限切れキャッシュの削除、孤立ファイルの検出といったガベージコレクション（GC）を担当。 主にCLIの `beautyspot gc` コマンドから呼び出される。 対象となる DB (`TaskDBMaintenable`) とストレージ (`BlobStorageMaintenable`) を受け取り、 複数のフェーズに分けてクリーンアップを実行する。

## 設計判断

### 5フェーズのクリーンアッププロセス

`clean_garbage()` は以下の順序で安全にGCを実行する： 1. 期限切れDBレコードの削除 2. Blobストレージの一時ファイル（`.spot_tmp`）のクリーンアップ 3. 孤立したBlobファイル（DBに存在しないファイル）の特定 4. 孤立ファイルの削除 5. 空ディレクトリの剪定

### Grace Period (猶予期間) の導入

実行中のタスクがBlobを書き込んだ直後で、まだDBにメタデータが保存されていない タイミングでGCが走ると、必要なファイルが孤立と誤認されるリスクがある。 これを防ぐため、`orphan_grace_seconds`（デフォルト60秒）より新しいファイルは 孤立判定から除外する設計とした。

## 実装メモ

- 孤立ファイルの検出 `scan_garbage()` は、ストレージの全キーを列挙し、 DBの `get_blob_keys()` との差分を取ることで行う
- 複数プロジェクトを一括でGCするためのヘルパー `scan_orphan_projects()` も提供される

## 実装概要 `MaintenanceService` クラスがDBとBlobストレージ間の整合性チェック、 期限切れキャッシュの削除、孤立ファイルの検出といったガベージコレクション（GC）を担当。 主にCLIの `beautyspot gc` コマンドから呼び出される。 対象となる DB (`TaskDBMaintenable`) とストレージ (`BlobStorageMaintenable`) を受け取り、 複数のフェーズに分けてクリーンアップを実行する。 ## 設計判断 ### 5フェーズのクリーンアッププロセス `clean_garbage()` は以下の順序で安全にGCを実行する： 1. 期限切れDBレコードの削除 2. Blobストレージの一時ファイル（`.spot_tmp`）のクリーンアップ 3. 孤立したBlobファイル（DBに存在しないファイル）の特定 4. 孤立ファイルの削除 5. 空ディレクトリの剪定 ### Grace Period (猶予期間) の導入 実行中のタスクがBlobを書き込んだ直後で、まだDBにメタデータが保存されていない タイミングでGCが走ると、必要なファイルが孤立と誤認されるリスクがある。 これを防ぐため、`orphan_grace_seconds`（デフォルト60秒）より新しいファイルは 孤立判定から除外する設計とした。 ## 実装メモ - 孤立ファイルの検出 `scan_garbage()` は、ストレージの全キーを列挙し、 DBの `get_blob_keys()` との差分を取ることで行う - 複数プロジェクトを一括でGCするためのヘルパー `scan_orphan_projects()` も提供される

references: src/beautyspot/maintenance.py

親: SPEC020

子: —