active: true
derived: false
gherkin: |
  Feature: MaintenanceService
    Scenario: Cleaning up expired tasks and orphaned blobs
      Given a MaintenanceService instance
      When clean_garbage is executed
      Then it removes expired cache entries from the database and deletes orphaned blob files
groups:
- MAINT
header: |
  MaintenanceService
level: '2.20'
links:
- ARCH010: fI3ChnJRbqIhdRSivmb1UxR5M9l1VFI4CmnTPt7dAKY=
normative: true
ref: ''
reviewed: zrBB495_EUfzqum_f0CCrkTolt2EDYaeTsJuRFgeiQ4=
text: |
  ## インターフェース

  ```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）で判定する。

  ## 設計判断

  長期間の運用で蓄積される不要なキャッシュデータや期限切れデータを、手動または自動で安全に削除・整理し、システムをクリーンな状態に保つためのメンテナンスAPIを定義するため。
