# 通知設計書 12-sd_notify（READY）通知

## 概要

本ドキュメントは、OpenSearchノードの起動完了時にsystemdサービスマネージャに対してサービス準備完了を通知するsd_notify（READY=1）通知の設計を記述する。

### 本通知の処理概要

sd_notify（READY）通知は、OpenSearchノードがすべての初期化処理を完了した後にsystemdに対して「READY=1」メッセージを送信し、サービスが正常に稼働可能な状態であることを通知する仕組みである。

**業務上の目的・背景**：systemd環境でOpenSearchをサービスとして運用する場合、systemdはサービスの起動完了を検知する必要がある。サービスタイプがnotifyに設定されている場合、systemdはsd_notifyによるREADY=1シグナルを待ち受ける。この通知がなければ、systemdはサービスの起動に失敗したとみなしてタイムアウトエラーとなる。本通知により、systemdは正確にサービスの起動完了を把握でき、依存サービスの起動や監視の開始が可能になる。

**通知の送信タイミング**：SystemdModulePluginのonNodeStarted()コールバックが呼ばれた時点で送信される。これはOpenSearchノードの全初期化処理が完了した後に呼ばれるプラグインライフサイクルコールバックである。

**通知の受信者**：Linux systemdサービスマネージャが受信者である。NOTIFY_SOCKETソケットを通じてsd_notify関数で通知される。

**通知内容の概要**：文字列「READY=1」がsd_notify関数を通じて送信される。

**期待されるアクション**：systemdはサービスの起動完了を認識し、サービスを「active (running)」状態に遷移させる。また、EXTEND_TIMEOUT通知のスケジュールタスクがキャンセルされる。

## 通知種別

OS（systemd）ネイティブ通知（sd_notifyシステムコール経由）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（sd_notify JNA呼び出し） |
| 優先度 | 高（起動完了の必須通知） |
| リトライ | なし（失敗時はRuntimeExceptionをスローして起動失敗とする） |

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

環境変数OPENSEARCH_SD_NOTIFYがtrueに設定されている場合にのみ通知が有効化される。systemdソケットのパスはNOTIFY_SOCKET環境変数からlibsystemdが自動的に取得する。

## 通知テンプレート

### メール通知の場合

該当なし（systemdネイティブ通知）。

### 本文テンプレート

```
READY=1
```

### 添付ファイル

該当なし。

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| unset_environment | 0固定（NOTIFY_SOCKETを維持） | ハードコーディング | Yes |
| state | "READY=1" | ハードコーディング | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| ノードライフサイクル | onNodeStarted()コールバック | enabled == true | ノード起動完了時にプラグインフレームワークから呼ばれる |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| enabled == false | 環境変数OPENSEARCH_SD_NOTIFYがtrue以外の場合、通知は送信されない |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[ノード起動完了] --> B[onNodeStarted呼び出し]
    B --> C{enabled?}
    C -->|No| D[何もしない・extenderはnull]
    C -->|Yes| E[sd_notify 0, READY=1 呼び出し]
    E --> F{戻り値 rc}
    F -->|rc >= 0| G[EXTEND_TIMEOUTスケジューラをキャンセル]
    F -->|rc < 0| H[RuntimeExceptionスロー・起動失敗]
    G --> I[起動完了]
    H --> I
```

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

### 参照テーブル一覧

該当なし（OSレベルの通知のため、データベースアクセスは発生しない）。

### 更新テーブル一覧

該当なし。

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| sd_notify失敗 | sd_notifyが負の値を返した場合 | RuntimeExceptionをスローし、ノード起動を失敗させる |
| 環境変数不正 | OPENSEARCH_SD_NOTIFYがtrue/false以外の値 | コンストラクタでRuntimeExceptionをスロー |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | なし |
| リトライ間隔 | なし |
| リトライ対象エラー | なし（失敗時は即座にRuntimeExceptionをスロー） |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | なし（ノード起動時に1回のみ） |
| 1日あたり上限 | なし |

### 配信時間帯

制限なし（ノード起動時に即座に送信）。

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

- sd_notify呼び出しはUNIXドメインソケット（NOTIFY_SOCKET）を経由するため、ネットワーク上の盗聴リスクはない
- libsystemd.so.0のネイティブライブラリをJNA経由でロードするため、AccessController.doPrivilegedによるセキュリティ制御が適用されている

## 備考

- 本通知はLinux systemd環境でのみ動作する
- READY通知の送信に成功すると、No.13のEXTEND_TIMEOUTスケジュールタスクがキャンセルされる
- READY通知の失敗はノード起動の失敗として扱われる（No.14のSTOPPING通知とは異なる扱い）

---

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

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

### 推奨読解順序

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

JNAを通じたネイティブ呼び出しのインターフェースを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Libsystemd.java | `modules/systemd/src/main/java/org/opensearch/systemd/Libsystemd.java` | sd_notifyネイティブメソッドの引数（unset_environment, state）の意味を理解する |

**読解のコツ**: JNAのNative.register()でlibsystemd.so.0をロードし、sd_notifyをJavaから直接呼び出せるようにしている。

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

SystemdModulePluginのライフサイクルとREADY通知の発火を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | SystemdModulePlugin.java | `modules/systemd/src/main/java/org/opensearch/systemd/SystemdModulePlugin.java` | onNodeStarted()（132行目）でREADY通知を送信し、extenderをキャンセルする流れ |

**主要処理フロー**:
1. **69-83行目**: コンストラクタでOPENSEARCH_SD_NOTIFY環境変数を読み取り、enabled判定
2. **132-145行目**: onNodeStarted()でsd_notify(0, "READY=1")呼び出し、失敗時RuntimeException
3. **143-144行目**: extender（EXTEND_TIMEOUTスケジューラ）をキャンセル

#### Step 3: sd_notify呼び出しの詳細

実際のsd_notify関数呼び出しのラッパーを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | SystemdModulePlugin.java | `modules/systemd/src/main/java/org/opensearch/systemd/SystemdModulePlugin.java` | sd_notifyメソッド（125行目）がLibsystemd.sd_notifyを呼び出し、traceログを出力する |

**主要処理フロー**:
- **125-129行目**: Libsystemd.sd_notify()への委譲とtraceレベルのログ出力

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

```
Node.start()
    |
    +-- PluginLifecycleComponent.onNodeStarted()
            |
            +-- SystemdModulePlugin.onNodeStarted()
                    |
                    +-- SystemdModulePlugin.sd_notify(0, "READY=1")
                    |       |
                    |       +-- Libsystemd.sd_notify(0, "READY=1")
                    |               |
                    |               +-- [JNA] libsystemd.so.0 :: sd_notify()
                    |
                    +-- extender.cancel()
```

### データフロー図

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

OPENSEARCH_SD_NOTIFY --> SystemdModulePlugin          --> sd_notify(0, "READY=1")
  (環境変数)                .onNodeStarted()                |
                                                       --> systemd NOTIFY_SOCKET
                                                            (サービス準備完了通知)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| SystemdModulePlugin.java | `modules/systemd/src/main/java/org/opensearch/systemd/SystemdModulePlugin.java` | ソース | READY通知の送信ロジック |
| Libsystemd.java | `modules/systemd/src/main/java/org/opensearch/systemd/Libsystemd.java` | ソース | sd_notifyネイティブメソッドのJNAバインディング |
| SystemdModulePluginTests.java | `modules/systemd/src/test/java/org/opensearch/systemd/SystemdModulePluginTests.java` | テスト | READY通知のテスト |
