# 機能設計書 20-TTL After Finishedコントローラー

## 概要

本ドキュメントは、Kubernetes TTL After Finishedコントローラーの機能設計を記述する。完了したJobのTTL期限切れを監視し、期限切れJobを自動削除する。

### 本機能の処理概要

**業務上の目的・背景**：Jobが完了（成功または失敗）した後、そのリソースをいつまでもクラスタに残しておくとetcdの容量やリスト操作のパフォーマンスに影響する。TTL After Finishedコントローラーは、Jobの`spec.ttlSecondsAfterFinished`で指定されたTTL期間後に自動的にJobとその子Pod（カスケード削除）を削除することで、クラスタリソースの自動クリーンアップを実現する。

**機能の利用シーン**：CronJobで定期作成されるJobの自動削除、一時的なバッチジョブの完了後のクリーンアップ、テスト実行結果のJob自動削除。

**主要な処理内容**：
1. Job Informerからの完了Jobの検出
2. TTL期限切れの判定
3. TTL期限切れJobのカスケード削除（Foreground伝播）
4. TTL期限前のJobの遅延再キュー

**関連システム・外部連携**：API Server（Job削除）、Jobコントローラー（Job完了通知の源泉）、GarbageCollector（Foreground削除によるPod削除の連携）

**権限による制御**：Jobの読み取りと削除権限。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | TTL After Finishedコントローラーは直接の画面を持たない |

## 機能種別

コントローラー（Reconciliation Loop） / リソースライフサイクル管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| Job.spec.ttlSecondsAfterFinished | *int32 | - | 完了後の自動削除待ち時間（秒） | >= 0 |
| Job.status.conditions | []JobCondition | - | Job完了状態 | Complete or Failed |

### 入力データソース

- Kubernetes API Server: Job Informer

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| - | - | Jobの削除（出力はJobリソースの消去） |

### 出力先

- Kubernetes API Server: Job削除（Foreground伝播ポリシー）

## 処理フロー

### 処理シーケンス

```
1. Job Add/Updateイベント受信
   └─ needsCleanupチェック（TTL設定あり AND Job完了）
   └─ 条件を満たす場合のみエンキュー
2. workerがデキューしprocessJobを実行
3. processJob
   a. JobListerからJob取得（NotFound: 正常終了）
   b. processTTLで期限チェック
   c. TTL未到来の場合: enqueueAfterで遅延再キュー
   d. TTL到来の場合: API Serverから最新Job取得（sanity check）
   e. 最新Jobで再度TTLチェック
   f. Foreground伝播でJob削除（Preconditions: UID一致）
```

### フローチャート

```mermaid
flowchart TD
    A[Job Add/Update] --> B{TTL設定あり AND 完了?}
    B -->|No| C[スキップ]
    B -->|Yes| D[エンキュー]
    D --> E[processJob]
    E --> F{Job存在?}
    F -->|No| G[正常終了]
    F -->|Yes| H[processTTL: TTL判定]
    H --> I{TTL到来?}
    I -->|No| J[遅延再キュー: 残り時間]
    I -->|Yes| K[API Serverから最新Job取得]
    K --> L[最新JobでTTL再判定]
    L --> M{TTL到来?}
    M -->|No| N[遅延再キュー]
    M -->|Yes| O[Foreground削除: Preconditions UID]
    O --> P[JobDeletionDurationSecondsメトリクス記録]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | needsCleanup | ttlSecondsAfterFinished != nil AND (Complete or Failed) | 常時 |
| BR-02 | TTL計算 | Job完了時刻 + ttlSecondsAfterFinished <= 現在時刻で期限切れ | 常時 |
| BR-03 | 二重チェック | キャッシュからの判定後、API Serverの最新データで再確認 | TTL到来時 |
| BR-04 | Foreground削除 | PropagationPolicy=Foregroundで子Pod含むカスケード削除 | 削除時 |
| BR-05 | Preconditions | UID一致チェックで誤削除防止 | 削除時 |
| BR-06 | DeletionTimestampチェック | 既に削除中のJobは処理しない | 常時 |
| BR-07 | 時刻スキュー対応 | 未来の完了時刻を検出した場合は警告ログ出力 | 時刻スキュー検出時 |

### 計算ロジック

- 残り時間 = (Job完了時刻 + ttlSecondsAfterFinished) - 現在時刻
- 残り時間 <= 0: TTL期限切れ
- 残り時間 > 0: 残り時間後に再キュー
- Job完了時刻: status.conditions[Complete or Failed].lastTransitionTime

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| Job取得 | Jobs (etcd) | SELECT | 最新状態の確認（sanity check） |
| Job削除 | Jobs (etcd) | DELETE | Foreground伝播によるカスケード削除 |

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

#### Jobs (etcd)

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| DELETE | - | Preconditions: UID一致 | Foreground伝播ポリシー |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | NotFound | Job既に削除済み | 正常としてスキップ |
| - | API通信エラー | Job取得/削除の失敗 | RateLimited requeue |
| - | 完了時刻取得失敗 | ConditionにlastTransitionTimeが未設定 | エラーとしてrequeue |

### リトライ仕様

- processJob失敗時: RateLimited requeue
- TTL未到来: 残り時間後にdelayed requeue

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

削除操作はPreconditions（UID一致）で保護される。Jobが別のリソースに置き換わっている場合は誤削除を防止する。Foreground伝播により、Job削除後にGarbageCollectorが子Podを削除する。

## パフォーマンス要件

- ワーカー数: 起動時に指定
- JobDeletionDurationSecondsメトリクス: TTL到来から実際の削除までの時間を計測
- RateLimitingQueue: デフォルトのexponential backoff

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

- Job削除はカスケード削除を伴うため、関連するPodも全て削除される
- Preconditionsチェックにより、UID不一致の場合の誤削除を防止

## 備考

- needsCleanup: `job.Spec.TTLSecondsAfterFinished != nil && jobutil.IsJobFinished(job)`
- jobFinishTime: Complete or FailedのConditionからlastTransitionTimeを取得
- 二重チェック（キャッシュ → 最新データ）はTTLが変更される可能性に対応
- メトリクス: JobDeletionDurationSeconds（TTL期限切れから削除までの遅延）

---

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

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

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ttlafterfinished_controller.go | `pkg/controller/ttlafterfinished/ttlafterfinished_controller.go` | Controller構造体（54-70行目） |

**読解のコツ**: clock.Clock インターフェースを使用してテスタビリティを確保している。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ttlafterfinished_controller.go | `pkg/controller/ttlafterfinished/ttlafterfinished_controller.go` | New（73-105行目）: Informerハンドラ登録 |
| 2-2 | ttlafterfinished_controller.go | `pkg/controller/ttlafterfinished/ttlafterfinished_controller.go` | Run（108-131行目）: ワーカー起動 |

**主要処理フロー**:
1. **73-105行目**: New: Job InformerにAdd/Updateハンドラ登録、clock初期化
2. **108-131行目**: Run: キャッシュ同期後にワーカー起動
3. **133-140行目**: addJob: TTL対象Jobのエンキュー
4. **143-150行目**: updateJob: TTL対象Jobのエンキュー
5. **206-261行目**: processJob: メインの処理ロジック

#### Step 3: TTL処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ttlafterfinished_controller.go | `pkg/controller/ttlafterfinished/ttlafterfinished_controller.go` | processJob（206-261行目）: 二重チェックとForeground削除 |
| 3-2 | ttlafterfinished_controller.go | `pkg/controller/ttlafterfinished/ttlafterfinished_controller.go` | processTTL（265-285行目）: TTL期限判定 |
| 3-3 | ttlafterfinished_controller.go | `pkg/controller/ttlafterfinished/ttlafterfinished_controller.go` | needsCleanup（288-290行目）: クリーンアップ必要性判定 |
| 3-4 | ttlafterfinished_controller.go | `pkg/controller/ttlafterfinished/ttlafterfinished_controller.go` | timeLeft（305-317行目）: 残り時間計算 |
| 3-5 | ttlafterfinished_controller.go | `pkg/controller/ttlafterfinished/ttlafterfinished_controller.go` | jobFinishTime（320-333行目）: Job完了時刻取得 |

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

```
New (初期化)
    |
    +-- Run (ワーカー起動)
        |
        +-- worker -> processNextWorkItem -> processJob
                |
                +-- jLister.Jobs().Get (キャッシュからJob取得)
                +-- processTTL (TTL期限判定)
                |       +-- needsCleanup
                |       +-- timeLeft
                |               +-- getFinishAndExpireTime
                |                       +-- jobFinishTime
                |
                +-- client.BatchV1().Jobs().Get (API Serverから最新Job取得)
                +-- processTTL (二度目のTTL判定)
                +-- client.BatchV1().Jobs().Delete (Foreground削除)
                +-- metrics.JobDeletionDurationSeconds.Observe
```

### データフロー図

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

Job Informer          --> addJob/updateJob
(Add/Update)              |
                          +-- needsCleanup? --No--> スキップ
                          |
                          +--Yes--> queue --> processJob
                                              |
                                              +-- processTTL
                                              |   (キャッシュ)
                                              |
                                              +-- TTL到来 --> API Get (最新確認)
                                              |               |
                                              |               +-- processTTL (最新)
                                              |               |
                                              |               +-- TTL到来 --> Delete (API Server)
                                              |
                                              +-- TTL未到来 --> enqueueAfter (残り時間)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ttlafterfinished_controller.go | `pkg/controller/ttlafterfinished/ttlafterfinished_controller.go` | ソース | メインコントローラーロジック |
| metrics/ | `pkg/controller/ttlafterfinished/metrics/` | ソース | Prometheusメトリクス（JobDeletionDurationSeconds） |
| util/ | `pkg/controller/job/util/` | ソース | IsJobFinished（Job完了判定ユーティリティ） |
