# 機能設計書 89-キャッシュ操作

## 概要

本ドキュメントは、Medusaコマースプラットフォームにおけるキャッシュ操作機能の設計について記述する。キャッシュモジュールの中核機能として、キャッシュデータの取得・設定・削除を行う。

### 本機能の処理概要

**業務上の目的・背景**：ECサイトでは、商品情報、価格情報、在庫情報など、頻繁にアクセスされるデータが存在する。キャッシュ操作機能は、これらのデータをキャッシュに保存することで、データベースへのアクセス負荷を軽減し、レスポンス時間を短縮する。システムのスケーラビリティ向上、ユーザー体験の改善を実現する。

**機能の利用シーン**：API応答のキャッシュ、クエリ結果のキャッシュ、セッション情報の一時保存、レート制限用のカウンター管理などで利用される。

**主要な処理内容**：
1. キャッシュ取得（get）：キーまたはタグを指定してキャッシュを取得
2. キャッシュ設定（set）：キー、データ、TTL、タグを指定してキャッシュを保存
3. キャッシュクリア（clear）：キーまたはタグを指定してキャッシュを削除
4. キー計算（computeKey）：入力データからキャッシュキーを計算
5. タグ計算（computeTags）：入力データからキャッシュタグを計算

**関連システム・外部連携**：キャッシュプロバイダー（メモリ/Redis等）、キャッシュ戦略（タグ計算ロジック）と連携する。

**権限による制御**：キャッシュ操作自体には直接的な権限制御はないが、キャッシュ対象データのアクセス制御は元データの権限に依存する。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | （画面未実装）| - | 本機能は内部API/バックグラウンド処理で利用 |

## 機能種別

キャッシュ管理 / データ取得・保存

## 入力仕様

### 入力パラメータ

#### キャッシュ取得（get）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| key | string | No | キャッシュキー | keyまたはtagsのいずれか必須 |
| tags | string[] | No | タグ一覧 | keyまたはtagsのいずれか必須 |
| providers | string[] | No | 使用するプロバイダー | デフォルトプロバイダーを使用 |

#### キャッシュ設定（set）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| key | string | Yes | キャッシュキー | 空文字不可 |
| data | object | Yes | キャッシュするデータ | - |
| ttl | number | No | 有効期限（秒） | デフォルト: 3600 |
| tags | string[] | No | タグ一覧 | 未指定時は自動計算 |
| providers | string[]/object[] | No | 使用するプロバイダー | プロバイダーごとにTTL設定可能 |
| options.autoInvalidate | boolean | No | 自動無効化フラグ | デフォルト: true |

#### キャッシュクリア（clear）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| key | string | No | キャッシュキー | keyまたはtagsのいずれか必須 |
| tags | string[] | No | タグ一覧 | keyまたはtagsのいずれか必須 |
| options.autoInvalidate | boolean | No | 自動無効化フラグ | - |
| providers | string[] | No | 使用するプロバイダー | - |

### 入力データソース

内部API呼び出し、ワークフローからの呼び出し

## 出力仕様

### 出力データ

#### get

| 項目名 | 型 | 説明 |
|--------|-----|------|
| data | any/null | キャッシュデータ（存在しない場合はnull） |

#### set

| 項目名 | 型 | 説明 |
|--------|-----|------|
| void | - | 戻り値なし |

#### clear

| 項目名 | 型 | 説明 |
|--------|-----|------|
| void | - | 戻り値なし |

### 出力先

キャッシュストレージ（メモリ/Redis等）

## 処理フロー

### 処理シーケンス

```
1. キャッシュ取得
   └─ キーまたはタグの検証
   └─ 重複リクエストチェック（ongoingRequests）
   └─ プロバイダーからデータ取得

2. キャッシュ設定
   └─ キーの検証
   └─ タグ計算（未指定時）
   └─ 重複リクエストチェック
   └─ プロバイダーにデータ保存

3. キャッシュクリア
   └─ キーまたはタグの検証
   └─ 重複リクエストチェック
   └─ プロバイダーからデータ削除
```

### フローチャート

```mermaid
flowchart TD
    A[get/set/clear要求] --> B{key/tags検証}
    B -->|無効| C[エラー返却]
    B -->|有効| D{重複リクエスト?}
    D -->|あり| E[既存Promiseを返却]
    D -->|なし| F[新規Promise作成]
    F --> G[ongoingRequestsに登録]
    G --> H[プロバイダー操作]
    H --> I[ongoingRequestsから削除]
    I --> J[結果返却]
    E --> J
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-89-1 | key/tags必須 | getとclearではkeyまたはtagsのいずれかが必須 | get/clear時 |
| BR-89-2 | key必須 | setではkeyが必須 | set時 |
| BR-89-3 | 重複リクエスト防止 | 同一key/tagsの同時リクエストは1つにまとめる | 全操作 |
| BR-89-4 | デフォルトTTL | TTL未指定時は1時間（3600秒） | set時 |
| BR-89-5 | 自動タグ計算 | tags未指定時はstrategy.computeTagsで計算 | set時 |
| BR-89-6 | 自動無効化 | autoInvalidate=trueのエントリは関連データ変更時に自動削除 | clear時 |
| BR-89-7 | ワイルドカード | tags=["*"]で全キャッシュをクリア | clear時 |

### 計算ロジック

重複リクエストキーの計算：
- `${key}|${tags.sort().join(",")}|${providers.join(",")}`

## データベース操作仕様

### 操作別データベース影響一覧

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| get | - | - | DBアクセスなし（キャッシュストレージのみ） |
| set | - | - | DBアクセスなし（キャッシュストレージのみ） |
| clear | - | - | DBアクセスなし（キャッシュストレージのみ） |

※キャッシュモジュールは永続化ストレージを使用しない。プロバイダーがRedisの場合はRedisに保存される。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| INVALID_ARGUMENT | 引数エラー | keyもtagsも未指定（get/clear） | keyまたはtagsを指定 |
| INVALID_ARGUMENT | 引数エラー | key未指定（set） | keyを指定 |
| PROVIDER_ERROR | プロバイダーエラー | キャッシュプロバイダー接続エラー | 次のプロバイダーで再試行 |

### リトライ仕様

- プロバイダーエラー発生時は警告ログを出力し、次のプロバイダーで再試行
- 全プロバイダーで失敗した場合はnullを返却（get）または無視（set/clear）

## トランザクション仕様

- キャッシュ操作はトランザクション対象外
- 複数プロバイダーへの操作は並列実行（アトミック性なし）

## パフォーマンス要件

- キャッシュ取得：10ms以内（メモリキャッシュ）、50ms以内（Redis）
- キャッシュ設定：非同期実行のため呼び出し元への影響なし
- メモリキャッシュ上限：デフォルト300MB

## セキュリティ考慮事項

- 機密データのキャッシュは慎重に行う
- キャッシュキーに機密情報を含めない
- 適切なTTL設定で古いデータの残存を防止

## 備考

- デフォルトTTLは1時間（ONE_HOUR_IN_SECOND = 60 * 60）
- setは非同期実行（void provider.set()）で呼び出し元をブロックしない
- traceGet/traceSet/traceClearでトレーシングをフック可能

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: サービス構造を理解する

CachingModuleServiceの全体構造を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | cache-module.ts | `packages/modules/caching/src/services/cache-module.ts` | クラス構造、依存性注入、フック |

**読解のコツ**: CachingModuleServiceはICachingModuleServiceを実装。providerService、strategy、ongoingRequestsの3つが主要な依存。

#### Step 2: キャッシュ取得を理解する

getメソッドの実装。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | cache-module.ts | `packages/modules/caching/src/services/cache-module.ts` | get, get_, performCacheGetメソッド |

**主要処理フロー**:
- **145-155行目**: `get`メソッド（トレーシングフック対応）
- **157-190行目**: `get_`メソッド
  - **166-171行目**: key/tagsの存在チェック
  - **173-178行目**: 重複リクエストチェック
  - **180-189行目**: 実行後にongoingRequestsから削除
- **192-216行目**: `performCacheGet`メソッド
  - **199-206行目**: 各プロバイダーからデータ取得を試行
  - **207-210行目**: エラー時は警告ログを出力して次へ

#### Step 3: キャッシュ設定を理解する

setメソッドの実装。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | cache-module.ts | `packages/modules/caching/src/services/cache-module.ts` | set, set_, performCacheSetメソッド |

**主要処理フロー**:
- **218-236行目**: `set`メソッド（トレーシングフック対応）
- **238-296行目**: `set_`メソッド
  - **255-259行目**: keyの存在チェック
  - **262-263行目**: tags未指定時は自動計算
  - **280-287行目**: 実行後にongoingRequestsから削除
- **298-319行目**: `performCacheSet`メソッド
  - **311行目**: `void provider.set()`で非同期実行

#### Step 4: キャッシュクリアを理解する

clearメソッドの実装。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | cache-module.ts | `packages/modules/caching/src/services/cache-module.ts` | clear, clear_, performCacheClearメソッド |

**主要処理フロー**:
- **321-337行目**: `clear`メソッド（トレーシングフック対応）
- **339-375行目**: `clear_`メソッド
  - **352-357行目**: key/tagsの存在チェック
- **377-394行目**: `performCacheClear`メソッド
  - **392行目**: `void provider.clear()`で非同期実行

#### Step 5: アプリケーションライフサイクルを理解する

起動/シャットダウン時のフック処理。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | cache-module.ts | `packages/modules/caching/src/services/cache-module.ts` | __hooks, onApplicationStart, onApplicationShutdownメソッド |

**主要処理フロー**:
- **69-79行目**: `__hooks`定義
- **81-104行目**: `onApplicationStart`メソッド
  - **82-84行目**: JoinerConfigからスキーマを構築
  - **92-98行目**: GraphQLスキーマを解析してストラテジーに渡す
- **106-112行目**: シャットダウン処理

### プログラム呼び出し階層図

```
API / ワークフロー
    │
    └─ CachingModuleService
           │
           ├─ get() / set() / clear()
           │      │
           │      ├─▶ traceGet/Set/Clear（トレーシング）
           │      │
           │      └─▶ get_() / set_() / clear_()
           │             │
           │             ├─▶ getRequestKey() / getClearRequestKey()
           │             │
           │             ├─▶ ongoingRequests.get/set/delete()
           │             │
           │             └─▶ performCacheGet/Set/Clear()
           │                    │
           │                    └─▶ providerService.retrieveProvider()
           │                           │
           │                           └─▶ provider.get/set/clear()
           │
           ├─ computeKey()
           │      └─▶ strategy.computeKey()
           │
           └─ computeTags()
                  └─▶ strategy.computeTags()
```

### データフロー図

```
[入力]                      [処理]                                [出力]

get要求 ───▶ CachingModuleService.get() ───▶ キャッシュデータ or null
     │               │
     ├─ key          ├─▶ 重複リクエストチェック
     ├─ tags         │
     └─ providers    └─▶ provider.get()

set要求 ───▶ CachingModuleService.set() ───▶ void
     │               │
     ├─ key          ├─▶ タグ計算（未指定時）
     ├─ data         │
     ├─ ttl          └─▶ void provider.set()（非同期）
     └─ tags

clear要求 ───▶ CachingModuleService.clear() ───▶ void
     │               │
     ├─ key          └─▶ void provider.clear()（非同期）
     └─ tags
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| cache-module.ts | `packages/modules/caching/src/services/cache-module.ts` | サービス | キャッシュ操作の主要ロジック |
| cache-provider.ts | `packages/modules/caching/src/services/cache-provider.ts` | サービス | プロバイダー管理 |
| memory-cache.ts | `packages/modules/caching/src/providers/memory-cache.ts` | プロバイダー | メモリキャッシュ実装 |
| strategy.ts | `packages/modules/caching/src/utils/strategy.ts` | ユーティリティ | キー/タグ計算戦略 |
| index.ts | `packages/modules/caching/src/index.ts` | エクスポート | モジュールエクスポート |
