# 通知設計書 82-FailedRescale

## 概要

本ドキュメントは、Kubernetes HorizontalPodAutoscaler (HPA) コントローラによるスケール変更が失敗した際に発行される `FailedRescale` イベント通知の設計を記載する。

### 本通知の処理概要

HPA コントローラがメトリクスに基づいて算出した希望レプリカ数に対象リソースをスケールしようとしたが、Scale サブリソースの更新に失敗した場合にこの通知が発行される。

**業務上の目的・背景**：HPAによるオートスケーリングにおいて、実際のスケール操作（Scale サブリソースの更新）が失敗した場合、ワークロードが期待する負荷に対応できない状態が続く。この通知により、運用者はスケーリング障害を速やかに検知し、API サーバの状態やリソースクォータ等を確認できる。

**通知の送信タイミング**：reconcileAutoscaler 内でスケール変更が必要と判断され、Scale サブリソースの Update API 呼び出しが retry.RetryOnConflict を含むリトライ後も失敗した場合に発行される。

**通知の受信者**：HPA オブジェクトに関連付けられた Kubernetes Event として記録される。kubectl describe hpa や外部モニタリングシステムを通じて運用者・SRE が受信する。

**通知内容の概要**：新しいレプリカ数、スケール変更の理由、発生したエラーの詳細が含まれる。フォーマット：「New size: %d; reason: %s; error: %v」

**期待されるアクション**：運用者は API サーバの稼働状態、リソースクォータの余裕、対象リソースの状態（削除中でないか等）を確認し、必要に応じて手動スケーリングを実施する。

## 通知種別

Kubernetes Event（EventType: Warning）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（reconcile ループ内で即座に発行） |
| 優先度 | 高（Warning イベント） |
| リトライ | HPA の resyncPeriod ごとに自動再試行 |

### 送信先決定ロジック

HPA オブジェクト自体に対する Kubernetes Event として記録される。

## 通知テンプレート

### 本文テンプレート

```
New size: %d; reason: %s; error: %v
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| desiredReplicas | 新しい希望レプリカ数 | normalizeDesiredReplicas の計算結果 | Yes |
| rescaleReason | スケール変更の理由 | メトリクス名 + "above target" 等 | Yes |
| err | エラー詳細 | Scale Update API のエラー | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| コントローラ同期 | HPA reconcile ループ | Scale サブリソースの Update が RetryOnConflict 後も失敗 | API サーバへの更新失敗 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| rescale == false | 現在のレプリカ数と希望レプリカ数が同じ場合はスケール操作自体が行われない |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[reconcileAutoscaler] --> B[desiredReplicas != currentReplicas]
    B -->|Yes| C[retry.RetryOnConflict でスケール更新]
    C -->|成功| D[SuccessfulRescale イベント]
    C -->|失敗| E[FailedRescale イベント発行]
    E --> F[AbleToScale condition を False に設定]
    F --> G[ステータス更新]
    B -->|No| H[スケール不要]
```

## データベース参照・更新仕様

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| HorizontalPodAutoscaler | HPA スペック・ステータス取得 | Informer キャッシュ経由 |
| Scale subresource | スケール対象のレプリカ数取得・更新 | API サーバ直接 |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| Scale subresource | UPDATE（失敗） | レプリカ数の変更試行 |
| HorizontalPodAutoscaler.Status | UPDATE | conditions の更新 |
| Event | INSERT | Warning イベントの記録 |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| Conflict エラー | 他のコントローラが同時に Scale を更新 | RetryOnConflict で自動リトライ |
| API サーバ不通 | ネットワーク障害等 | resyncPeriod 後に自動リトライ |
| リソース不存在 | 対象リソースが削除済み | HPA が削除されるまで定期的にリトライ |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | RetryOnConflict: DefaultRetry（Conflict エラーのみ） |
| リトライ間隔 | DefaultRetry のバックオフ設定に準拠 |
| リトライ対象エラー | Conflict エラーのみ（他のエラーは即座に失敗） |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | Kubernetes Event レート制限に準拠 |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし

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

- エラーメッセージにリソース名が含まれるが、秘匿情報は含まない
- Event は RBAC により閲覧権限が制御される

## 備考

- この通知発行時には AbleToScale condition が False / FailedUpdateScale に設定される
- RetryOnConflict では最新の Scale オブジェクトを再取得してリトライする

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | types.go | `staging/src/k8s.io/api/autoscaling/v2/types.go` | HorizontalPodAutoscaler, HorizontalPodAutoscalerCondition を理解 |
| 1-2 | types.go | `staging/src/k8s.io/api/autoscaling/v1/types.go` | Scale subresource の構造を理解 |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | horizontal.go | `pkg/controller/podautoscaler/horizontal.go` | reconcileAutoscaler (行 759) のスケーリング判定 |

**主要処理フロー**:
1. **行 895**: rescale == true の判定
2. **行 896-920**: retry.RetryOnConflict によるスケール更新
3. **行 922-930**: エラー時の FailedRescale イベント発行
4. **行 924**: Eventf で "FailedRescale" を記録
5. **行 925**: AbleToScale condition を False に設定

#### Step 3: リトライロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | horizontal.go | `pkg/controller/podautoscaler/horizontal.go` | 行 896-920 の RetryOnConflict ブロック |

**主要処理フロー**:
- **行 903**: Scale Update API 呼び出し
- **行 910**: 失敗時に最新 Scale を再取得
- **行 919**: 元の updateErr を返してリトライ判定

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

```
HorizontalController.reconcileAutoscaler (行 759)
    |
    +-- computeReplicasForMetrics (行 854) ... レプリカ数計算
    |
    +-- normalizeDesiredReplicas / normalizeDesiredReplicasWithBehaviors
    |
    +-- retry.RetryOnConflict (行 896)
    |      |
    |      +-- scaleNamespacer.Scales().Update (行 903)
    |      +-- scaleNamespacer.Scales().Get (行 910) ... リトライ時
    |
    +-- eventRecorder.Eventf (行 924) ... FailedRescale 発行
    |
    +-- setCondition (行 925) ... AbleToScale = False
```

### データフロー図

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

HPA Spec ----------------> reconcileAutoscaler ---------> Event: FailedRescale
Scale Subresource -------> Scale.Update (失敗)          HPA Status (conditions)
Metrics -----------------> desiredReplicas 算出          エラーログ
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| horizontal.go | `pkg/controller/podautoscaler/horizontal.go` | ソース | HPA コントローラのメインロジック |
| retry.go | `k8s.io/client-go/util/retry/util.go` | ソース | RetryOnConflict ユーティリティ |
