# 機能設計書 14-失敗ジョブ管理

## 概要

本ドキュメントは、Laravel Frameworkの失敗ジョブ管理機能の設計を詳細に記述したものである。キュー処理で失敗したジョブの記録、参照、再実行、削除機能を提供し、Database、DynamoDB、Fileの各ストレージをサポートする。

### 本機能の処理概要

失敗ジョブ管理は、キュー処理で最大試行回数を超過したり、例外により失敗したジョブを永続化し、後から調査・再実行できる機能である。運用時のトラブルシューティングと障害回復に不可欠な機能を提供する。

**業務上の目的・背景**：非同期ジョブ処理において、一時的なエラー（ネットワーク障害、外部API障害等）や永続的なエラー（データ不整合、ロジックバグ等）により処理が失敗することは避けられない。失敗ジョブ管理は、これらの失敗を記録することで、原因調査と適切な対応（再実行または手動対処）を可能にする。また、失敗パターンの分析によるシステム改善にも活用される。

**機能の利用シーン**：
- 失敗したジョブの一覧確認と原因調査
- 一時的エラー解消後のジョブ再実行
- 古い失敗ジョブのクリーンアップ
- 失敗ジョブ数のモニタリングとアラート

**主要な処理内容**：
1. 失敗ジョブのログ記録（log メソッド）
2. 失敗ジョブの一覧取得（all, ids メソッド）
3. 個別の失敗ジョブ取得（find メソッド）
4. 失敗ジョブの削除（forget, flush メソッド）
5. 古い失敗ジョブの定期削除（prune メソッド）
6. 失敗ジョブ数のカウント（count メソッド）

**関連システム・外部連携**：
- データベース：失敗ジョブの永続化（DatabaseFailedJobProvider）
- DynamoDB：AWSでの失敗ジョブ管理（DynamoDbFailedJobProvider）
- ファイルシステム：ローカルファイルでの管理（FileFailedJobProvider）

**権限による制御**：失敗ジョブ管理自体は権限制御を持たない。Artisanコマンドによる操作はサーバーアクセス権限に依存。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 本機能は画面に直接関連しない |

## 機能種別

データ管理 / ログ記録 / 障害回復

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| connection | string | Yes（log時） | キュー接続名 | - |
| queue | string | Yes（log時） | キュー名 | - |
| payload | string | Yes（log時） | ジョブペイロード（JSON） | 有効なJSON |
| exception | Throwable | Yes（log時） | 発生した例外 | - |
| id | mixed | Yes（find/forget時） | 失敗ジョブID | - |
| hours | int/null | No（flush時） | 削除対象の経過時間（時間） | 正の整数 |
| before | DateTimeInterface | Yes（prune時） | 削除対象の日時閾値 | - |

### 入力データソース

- ワーカー：ジョブ失敗時に自動的にlogメソッドを呼び出し
- Artisanコマンド：queue:failed、queue:retry、queue:forget等

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| id | int/string | 失敗ジョブの一意識別子 |
| connection | string | キュー接続名 |
| queue | string | キュー名 |
| payload | string | ジョブペイロード（JSON） |
| exception | string | 例外情報 |
| failed_at | datetime | 失敗日時 |

### 出力先

- データベース：failed_jobsテーブル（デフォルト）
- DynamoDB：指定テーブル
- ファイル：指定パス

## 処理フロー

### 処理シーケンス

```
1. ジョブ失敗検知
   └─ Workerがジョブの失敗を検知
2. 失敗情報の収集
   └─ 接続名、キュー名、ペイロード、例外情報を取得
3. 失敗ジョブの記録
   └─ log() で永続化ストレージに保存
4. 失敗ジョブIDの返却
   └─ 記録されたジョブのIDを返却
```

### フローチャート

```mermaid
flowchart TD
    A[ジョブ失敗] --> B[失敗情報収集]
    B --> C[log 呼び出し]
    C --> D{プロバイダ種別}
    D -->|Database| E[DBにINSERT]
    D -->|DynamoDB| F[DynamoDBにPut]
    D -->|File| G[ファイルに追記]
    E --> H[IDを返却]
    F --> H
    G --> H
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-14-01 | 例外の文字コード変換 | 例外文字列はUTF-8に変換して保存 | log時 |
| BR-14-02 | 降順ソート | 失敗ジョブは新しい順にソート | all/ids取得時 |
| BR-14-03 | バッチ削除 | prune処理は1000件ずつバッチ削除 | prune時 |
| BR-14-04 | 時間ベースflush | hours指定時は指定時間以前のジョブのみ削除 | flush時 |

### 計算ロジック

```php
// 時間ベースフィルタリング
deleteTarget = Date::now()->subHours($hours)

// バッチ削除ループ
while ($deleted !== 0) {
    $deleted = $query->limit(1000)->delete();
    $totalDeleted += $deleted;
}
```

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| log | failed_jobs | INSERT | 失敗ジョブ情報を挿入 |
| ids | failed_jobs | SELECT | IDリストを取得 |
| all | failed_jobs | SELECT | 全件取得 |
| find | failed_jobs | SELECT | 個別取得 |
| forget | failed_jobs | DELETE | 個別削除 |
| flush | failed_jobs | DELETE | 条件付き全削除 |
| prune | failed_jobs | DELETE | 日時ベースの削除 |
| count | failed_jobs | COUNT | 件数取得 |

### テーブル別操作詳細

#### failed_jobs

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | id | AUTO_INCREMENT | プライマリキー |
| INSERT | connection | キュー接続名 | |
| INSERT | queue | キュー名 | |
| INSERT | payload | ジョブペイロードJSON | |
| INSERT | exception | 例外文字列（UTF-8変換後） | |
| INSERT | failed_at | Date::now() | 失敗日時 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | QueryException | DB接続エラー | DB接続設定を確認 |
| - | DynamoDbException | DynamoDB接続エラー | AWS設定を確認 |
| - | IOException | ファイル書き込みエラー | パーミッションを確認 |

### リトライ仕様

失敗ジョブ管理自体にリトライ機構はない。ジョブの再実行は queue:retry コマンドで実施。

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

各操作は個別のトランザクションで実行される。prune処理はバッチ単位でコミット。

## パフォーマンス要件

- prune処理は1000件単位のバッチ削除でメモリ効率を確保
- IDベースの取得にはインデックスを活用
- 大量の失敗ジョブがある場合はページネーションを推奨

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

- ペイロードに機密情報が含まれる可能性を考慮
- 例外情報のマスキングが必要な場合はカスタム実装
- DynamoDB使用時はIAMロールによるアクセス制御

## 備考

- CountableFailedJobProvider：count機能を提供するインターフェース
- PrunableFailedJobProvider：prune機能を提供するインターフェース
- FailedJobProviderInterface：基本操作を定義するインターフェース

---

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

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

### 推奨読解順序

#### Step 1: インターフェースを理解する

まず、失敗ジョブプロバイダのインターフェースを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | FailedJobProviderInterface.php | `src/Illuminate/Queue/Failed/FailedJobProviderInterface.php` | 基本操作の契約を確認 |
| 1-2 | CountableFailedJobProvider.php | `src/Illuminate/Queue/Failed/CountableFailedJobProvider.php` | count機能の契約を確認 |
| 1-3 | PrunableFailedJobProvider.php | `src/Illuminate/Queue/Failed/PrunableFailedJobProvider.php` | prune機能の契約を確認 |

**読解のコツ**: インターフェースを先に理解することで、各プロバイダの実装がどの契約を満たしているかが明確になる。

#### Step 2: Databaseプロバイダを理解する

最も一般的なDatabaseプロバイダの実装を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | DatabaseFailedJobProvider.php | `src/Illuminate/Queue/Failed/DatabaseFailedJobProvider.php` | コンストラクタとプロパティ（39-44行目） |
| 2-2 | DatabaseFailedJobProvider.php | `src/Illuminate/Queue/Failed/DatabaseFailedJobProvider.php` | logメソッド（55-64行目） |
| 2-3 | DatabaseFailedJobProvider.php | `src/Illuminate/Queue/Failed/DatabaseFailedJobProvider.php` | pruneメソッド（132-145行目） |

**主要処理フロー**:
1. **39-44行目**: コンストラクタで接続リゾルバ、DB名、テーブル名を設定
2. **55-64行目**: `log` - 失敗日時を取得し、例外をUTF-8変換後にINSERT
3. **72-79行目**: `ids` - キューでフィルタリングしてIDリストを取得
4. **132-145行目**: `prune` - 1000件単位でバッチ削除

#### Step 3: DynamoDBプロバイダを理解する

AWS環境向けのDynamoDBプロバイダを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | DynamoDbFailedJobProvider.php | `src/Illuminate/Queue/Failed/DynamoDbFailedJobProvider.php` | DynamoDB固有の実装を確認 |

**主要処理フロー**:
- DynamoDB APIを使用したPutItem、Scan、DeleteItem操作
- UUID v4によるID生成
- GSI（グローバルセカンダリインデックス）を使用したクエリ最適化

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

```
Worker::failJob($job, $exception)
    │
    └─ Job::fail($exception)
           │
           └─ FailedJobProviderInterface::log($connection, $queue, $payload, $exception)
                  │
                  ├─ DatabaseFailedJobProvider::log()
                  │      ├─ Date::now()
                  │      ├─ mb_convert_encoding($exception, 'UTF-8')
                  │      └─ Query::insertGetId(...)
                  │
                  ├─ DynamoDbFailedJobProvider::log()
                  │      ├─ Str::uuid()
                  │      └─ DynamoDbClient::putItem(...)
                  │
                  └─ FileFailedJobProvider::log()
                         └─ file_put_contents(...)
```

### データフロー図

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

ジョブ失敗        ───▶  FailedJobProvider::log()  ───▶  failed_jobs/DynamoDB/File
    │                        │
接続名・キュー名   ───▶  insertGetId()             ───▶  失敗ジョブID
    │                        │
ペイロード         ───▶  mb_convert_encoding()     ───▶  UTF-8変換済みデータ
    │                        │
例外情報          ───▶  (string) $exception       ───▶  例外文字列

Artisan queue:retry
    │
    └─────────────────▶  find($id)                ───▶  失敗ジョブレコード
                             │
                         Queue::push()            ───▶  再キューイング
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| DatabaseFailedJobProvider.php | `src/Illuminate/Queue/Failed/DatabaseFailedJobProvider.php` | ソース | DB永続化プロバイダ |
| DynamoDbFailedJobProvider.php | `src/Illuminate/Queue/Failed/DynamoDbFailedJobProvider.php` | ソース | DynamoDB永続化プロバイダ |
| FileFailedJobProvider.php | `src/Illuminate/Queue/Failed/FileFailedJobProvider.php` | ソース | ファイル永続化プロバイダ |
| NullFailedJobProvider.php | `src/Illuminate/Queue/Failed/NullFailedJobProvider.php` | ソース | Nullプロバイダ（記録なし） |
| FailedJobProviderInterface.php | `src/Illuminate/Queue/Failed/FailedJobProviderInterface.php` | インターフェース | 基本操作契約 |
| CountableFailedJobProvider.php | `src/Illuminate/Queue/Failed/CountableFailedJobProvider.php` | インターフェース | カウント機能契約 |
| PrunableFailedJobProvider.php | `src/Illuminate/Queue/Failed/PrunableFailedJobProvider.php` | インターフェース | プルーニング機能契約 |
| QueueServiceProvider.php | `src/Illuminate/Queue/QueueServiceProvider.php` | ソース | プロバイダ登録 |
