active: true
derived: false
groups:
- STORE
header: |
  Blobストレージ構成
level: 2.4
links:
- REQ004: MAkJGJurzARw41s-hmBMRt7LcMDuyoFDRgaAIUmIabE=
normative: true
ref: ''
reviewed: rkU3uTAxpVsgdsm0HQ8GMM_MLqkLbPCOt2tRCeu5l2g=
text: |
  ## コンポーネント構成

  ```mermaid
  graph TD
    A[core.Spot] -->|判定| B[StoragePolicyProtocol];
    A -->|保存/読込| C[BlobStorageBase];
    D[LocalStorage] --> C;
    E[S3Storage] --> C;
    A -->|メタデータ| F[TaskDBBase];
  ```

  ## コンポーネント責務

  | コンポーネント | 責務 | インターフェース |
  |---|---|---|
  | StoragePolicyProtocol | データのサイズ等に基づき、DB保存かBlob保存かを判定する | `should_save_as_blob()` |
  | BlobStorageBase | 大規模データの外部ストレージ保存を抽象化する | `save()`, `load()`, `delete()` |
  | LocalStorage | ローカルファイルシステムへのアトミックな保存と検証 | `base_dir`, `os.replace` |
  | S3Storage | AWS S3互換オブジェクトストレージへの保存 | `s3://` URI, `boto3` |

  ## データフロー

  ```mermaid
  sequenceDiagram
    participant Spot as core.Spot
    participant Policy as StoragePolicy
    participant DB as TaskDB
    participant Blob as BlobStorage

    Spot->>Policy: should_save_as_blob(data)
    alt Policy: True (Blob保存)
      Spot->>Blob: save(key, data)
      Blob-->>Spot: location (path/URI)
      Spot->>DB: insert(metadata, storage_type=FILE, blob_key=location)
    else Policy: False (Inline保存)
      Spot->>DB: insert(metadata, storage_type=DIRECT_BLOB, result_data=data)
    end
  ```

  ## 技術選定

  | 技術領域 | 選定 | 理由 |
  |---|---|---|
  | 保存判定 | 閾値ベース (Threshold) | DBの肥大化を防ぎつつ、小容量データのI/Oを最適化
  | アトミック性 | 一時ファイル + Rename | 保存中のクラッシュや並行書き込みによる破損を完全に防止 |
  | クラウド対応 | Boto3 (S3) | 業界標準のプロトコルによる高い互換性とスケーラビリティ |

  ## 非機能要件方針

  -   **安全性**: LocalStorage では `is_relative_to` によるパストラバーサル防止を徹底

  -   **信頼性**: 保存時は `fsync` を実行し、OSレベルでのデータ到達を確認

  -   **効率性**: S3 保存時は `upload_fileobj` を使用し、5GB超のマルチパートアップロードに自動対応
