# 通知設計書 18-LeaderChecker通知

## 概要

本ドキュメントは、フォロワーノードがリーダーノードへの定期的なヘルスチェックを実行し、リーダー障害を検出してクラスタ調整層に通知するLeaderChecker通知の設計を記述する。

### 本通知の処理概要

LeaderCheckerは、フォロワーノードがリーダーノードに対して定期的にヘルスチェックリクエストを送信し、応答の成功・失敗を監視する。設定されたリトライ回数を超えて連続失敗した場合、または接続切断やヘルスチェック失敗を検出した場合に、リーダー障害をonLeaderFailureコールバックを通じて通知する。

**業務上の目的・背景**：OpenSearchクラスタでは、リーダーノード（クラスタマネージャ）が障害を起こした場合に速やかに検出し、新たなリーダー選出プロセスを開始する必要がある。LeaderCheckerはこの障害検出メカニズムの中核を担い、フォロワーがリーダーの健全性を継続的に監視する。リーダー障害の検出により、フォロワーはCANDIDATEモードに遷移して新たなリーダー選出を試みる。

**通知の送信タイミング**：(1) ヘルスチェックの連続失敗回数がleaderCheckRetryCount（デフォルト3）を超えた場合。(2) 接続切断（ConnectTransportException）を検出した場合。(3) リーダーのヘルスチェックが失敗（NodeHealthCheckFailureException）した場合。(4) TransportConnectionListenerによるリーダーノード切断検出時。

**通知の受信者**：Coordinatorクラスのリーダー障害ハンドラ（Consumer<Exception> onLeaderFailure）が受信者である。

**通知内容の概要**：障害の原因となったException（ConnectTransportException、NodeHealthCheckFailureException、OpenSearchException等）が通知される。

**期待されるアクション**：Coordinatorがフォロワーモードを離脱し、CANDIDATEモードに遷移して新たなリーダー選出プロセスを開始する。

## 通知種別

プロセス内コールバック通知（Consumer<Exception>による非同期通知）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（generic ThreadPoolで実行） |
| 優先度 | 最高（クラスタ可用性に直結） |
| リトライ | チェック自体がリトライ機構（デフォルト3回失敗で通知） |

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

updateLeader()でリーダーノードが設定されると、CheckSchedulerが開始される。チェック対象は常に現在のリーダーノード1台のみ。

## 通知テンプレート

### メール通知の場合

該当なし。

### 本文テンプレート

```
該当なし（Exception オブジェクトが渡される）
```

### 添付ファイル

該当なし。

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| leader | リーダーノード情報 | CheckScheduler.leader | Yes |
| failureCount | 連続失敗回数 | failureCountSinceLastSuccess | Yes |
| exception | 障害原因の例外 | TransportException等 | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| トランスポート | ヘルスチェック応答エラー | 連続失敗回数 >= leaderCheckRetryCount | デフォルト3回連続失敗 |
| トランスポート | ConnectTransportException | 即座に通知 | 接続切断は即座にリーダー障害と判定 |
| トランスポート | NodeHealthCheckFailureException | 即座に通知 | リーダーが不健全と報告 |
| トランスポート | TransportConnectionListener.onNodeDisconnected | リーダーノードが切断 | リーダーとの接続断を即座に検出 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| CheckSchedulerがクローズ済み | isClosed==trueの場合は通知しない |
| 連続失敗回数が閾値未満 | リトライ回数未満の場合は次のチェックをスケジュール |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[updateLeader リーダー設定] --> B[CheckScheduler開始]
    B --> C[handleWakeUp]
    C --> D[LeaderCheckRequest送信]
    D --> E{応答結果}
    E -->|成功| F[failureCount=0 次のチェックスケジュール]
    E -->|ConnectTransportException| G[即座にleaderFailed]
    E -->|NodeHealthCheckFailureException| G
    E -->|その他エラー| H{failureCount >= retryCount?}
    H -->|Yes| G
    H -->|No| I[failureCount++ 次のチェックスケジュール]
    F --> C
    I --> C
    G --> J[isClosed CAS false->true]
    J --> K[clusterManagerMetrics カウンタ増加]
    K --> L[generic ThreadPoolでonLeaderFailure実行]
```

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

### 参照テーブル一覧

該当なし（インメモリ処理）。

### 更新テーブル一覧

該当なし。

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| ConnectTransportException | リーダーとの接続失敗 | 即座にleaderFailed()を呼び出し |
| NodeHealthCheckFailureException | リーダーが不健全と報告 | 即座にleaderFailed()を呼び出し |
| CoordinationStateRejectedException | リーダーがクラスタマネージャでない | リトライカウントに加算 |
| TransportException | その他のトランスポートエラー | リトライカウントに加算、閾値超過で通知 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | cluster.fault_detection.leader_check.retry_count（デフォルト3） |
| リトライ間隔 | cluster.fault_detection.leader_check.interval（デフォルト1000ms） |
| リトライ対象エラー | ConnectTransportExceptionとNodeHealthCheckFailureException以外のTransportException |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| チェック間隔 | cluster.fault_detection.leader_check.interval（デフォルト1000ms、最小100ms） |
| チェックタイムアウト | cluster.fault_detection.leader_check.timeout（デフォルト10000ms、最小1ms、最大60000ms） |

### 配信時間帯

制限なし（ノード稼働中は常時チェック）。

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

- ヘルスチェックリクエストはトランスポート層を経由するため、TLS/SSL設定に依存
- リーダーチェックのアクション名は内部API（"internal:coordination/fault_detection/leader_check"）
- リーダー側ではリクエスト送信者がクラスタメンバーであることを検証する（228-232行目）

## 備考

- leaderCheckTimeout設定はDynamic属性で動的変更可能
- CheckSchedulerはAtomicBooleanのisClosed、AtomicLongのfailureCountSinceLastSuccessでスレッド安全性を確保
- リーダー側のhandleLeaderCheck()では、ノードの健全性チェック、クラスタマネージャ状態確認、送信者のクラスタメンバーシップ確認の3段階の検証を行う
- clusterManagerMetrics.leaderCheckFailureCounterでリーダーチェック失敗のメトリクスを記録

---

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

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

### 推奨読解順序

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

チェックリクエストの構造と設定パラメータを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | LeaderChecker.java | `server/src/main/java/org/opensearch/cluster/coordination/LeaderChecker.java` | LeaderCheckRequest（403行目〜）の構造とSetting定義（90-113行目） |

**読解のコツ**: 3つのSetting（interval, timeout, retry_count）の関係を理解すること。intervalはチェック間隔、timeoutは1回のチェックのタイムアウト、retry_countは連続失敗許容回数。

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

LeaderCheckerのコンストラクタとリーダー更新処理を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | LeaderChecker.java | `server/src/main/java/org/opensearch/cluster/coordination/LeaderChecker.java` | コンストラクタ（127行目〜）でのリクエストハンドラ登録とConnectionListener登録 |
| 2-2 | LeaderChecker.java | `server/src/main/java/org/opensearch/cluster/coordination/LeaderChecker.java` | updateLeader()（179行目〜）でのCheckScheduler開始・停止 |

**主要処理フロー**:
1. **145-155行目**: LEADER_CHECK_ACTION_NAMEのリクエストハンドラを登録
2. **157-162行目**: TransportConnectionListenerを登録（ノード切断検出）
3. **179-194行目**: updateLeader()で旧CheckSchedulerをclose、新CheckSchedulerを開始

#### Step 3: チェック実行処理を理解する

CheckSchedulerの定期チェック処理フローを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | LeaderChecker.java | `server/src/main/java/org/opensearch/cluster/coordination/LeaderChecker.java` | CheckScheduler.handleWakeUp()（271行目〜）でのリクエスト送信とレスポンスハンドリング |

**主要処理フロー**:
- **279-283行目**: LeaderCheckRequestを送信
- **293-299行目**: 成功時はfailureCount=0にリセット、次のチェックをスケジュール
- **303-346行目**: 失敗時の分岐処理（接続切断/ヘルスチェック失敗/リトライ超過）

#### Step 4: リーダー障害通知を理解する

leaderFailed()メソッドの通知処理を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | LeaderChecker.java | `server/src/main/java/org/opensearch/cluster/coordination/LeaderChecker.java` | leaderFailed()（356行目〜）でのCAS操作とgenericスレッドでの通知実行 |

**主要処理フロー**:
- **357行目**: isClosed CAS false->true（二重通知防止）
- **358行目**: leaderCheckFailureCounterメトリクス増加
- **359-363行目**: generic ThreadPoolでonLeaderFailure.accept(e)を非同期実行

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

```
Coordinator
    |
    +-- LeaderChecker.updateLeader(leader)
            |
            +-- CheckScheduler(leader)
                    |
                    +-- handleWakeUp()
                    |       |
                    |       +-- transportService.sendRequest(LEADER_CHECK_ACTION_NAME)
                    |       |       |
                    |       |       +-- [成功] failureCount=0, scheduleNextWakeUp()
                    |       |       +-- [失敗] leaderFailed() or scheduleNextWakeUp()
                    |       |
                    |       +-- scheduleNextWakeUp() [1000ms後]
                    |
                    +-- handleDisconnectedNode(node)
                    |       |
                    |       +-- leaderFailed()
                    |
                    +-- leaderFailed(exception)
                            |
                            +-- clusterManagerMetrics.incrementCounter()
                            +-- generic.execute(onLeaderFailure.accept(e))
```

### データフロー図

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

LeaderCheckRequest      -->  TransportService.sendRequest()     --> [成功] scheduleNextWakeUp()
  sender: localNode              |                               --> [失敗] leaderFailed()
                             handleResponse/handleException              |
                                                                    --> onLeaderFailure.accept(exception)
                                                                         |
                                                                    --> Coordinator
                                                                        (CANDIDATE遷移)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| LeaderChecker.java | `server/src/main/java/org/opensearch/cluster/coordination/LeaderChecker.java` | ソース | リーダーチェック通知の主要実装 |
| Coordinator.java | `server/src/main/java/org/opensearch/cluster/coordination/Coordinator.java` | ソース | onLeaderFailureコールバックの提供元 |
| NodeHealthService.java | `server/src/main/java/org/opensearch/monitor/NodeHealthService.java` | ソース | ノードヘルスチェック |
| NodeHealthCheckFailureException.java | `server/src/main/java/org/opensearch/cluster/coordination/NodeHealthCheckFailureException.java` | ソース | ヘルスチェック失敗例外 |
| CoordinationStateRejectedException.java | `server/src/main/java/org/opensearch/cluster/coordination/CoordinationStateRejectedException.java` | ソース | 調整状態拒否例外 |
| ClusterManagerMetrics.java | `server/src/main/java/org/opensearch/cluster/ClusterManagerMetrics.java` | ソース | メトリクス記録 |
| LeaderCheckerTests.java | `server/src/test/java/org/opensearch/cluster/coordination/LeaderCheckerTests.java` | テスト | リーダーチェックのテスト |
