# バッチ設計書 2-AsyncRefreshTask

## 概要

本ドキュメントは、OpenSearchのインデックスサービスにおけるリフレッシュ処理を定期実行するバッチタスクの設計を記載する。

### 本バッチの処理概要

AsyncRefreshTaskは、インデックスレベルでリフレッシュ（内部Luceneリーダーの更新）を定期的に実行し、インデクシングされたドキュメントを検索可能にするバッチタスクである。

**業務上の目的・背景**：OpenSearchではドキュメントがインデクシングされた後、リフレッシュが実行されるまで検索結果に反映されない。リフレッシュはLuceneのIndexWriterからIndexReaderを再オープンする処理であり、ニアリアルタイム検索を実現するために定期的に実行される必要がある。本バッチにより、明示的なリフレッシュAPIの呼び出しなしに検索可能性が維持される。

**バッチの実行タイミング**：インデックスごとに`index.refresh_interval`（デフォルト1秒）の間隔で定期実行される。クラスタレベルのデフォルトリフレッシュ間隔も適用可能。

**主要な処理内容**：
1. リフレッシュ間隔が0より大きいか確認する（-1の場合は自動リフレッシュ無効）
2. インデックス内の全シャードを走査する
3. 各シャードに対して`scheduledRefresh()`を呼び出してリフレッシュを実行する

**前後の処理との関連**：リフレッシュ処理はインデクシング処理の後続として位置づけられる。AsyncReplicationTask（No.3）はリフレッシュ間隔と同じ間隔でセグメントレプリケーションを実行するため、関連が深い。シャードレベルリフレッシュ（AsyncShardRefreshTask, No.8）が有効な場合、本タスクの代わりにシャード単位で独立してリフレッシュが行われる。

**影響範囲**：対象インデックスの全シャードのLuceneリーダーが更新され、新しくインデクシングされたドキュメントが検索可能になる。リフレッシュ間隔はニアリアルタイム検索の遅延に直接影響する。

## バッチ種別

データ同期処理（Luceneインデックスのリフレッシュ・検索可能化）

## 実行スケジュール

| 項目 | 内容 |
|-----|------|
| 実行頻度 | 定期実行（デフォルト1秒間隔） |
| 実行時刻 | インデックスのライフサイクルに依存（常時） |
| 実行曜日 | 該当なし（常時稼働） |
| 実行日 | 該当なし（常時稼働） |
| トリガー | タイマーベースの定期スケジュール（AbstractAsyncTask）。固定間隔スケジューリング対応。 |

## 実行条件

### 前提条件

| 条件 | 説明 |
|-----|------|
| IndexServiceが未クローズ | `indexService.closed.get() == false`であること |
| インデックスがOPEN状態 | `IndexMetadata.State.OPEN`であること |
| リフレッシュ間隔が0より大きい | `getRefreshInterval().millis() > 0`であること（-1は無効化） |

### 実行可否判定

BaseAsyncTaskの`mustReschedule()`により、IndexServiceがクローズされておらずインデックスがOPEN状態の場合にのみ再スケジューリングされる。`maybeRefreshEngine(false)`内で、リフレッシュ間隔が0ms以下の場合は処理がスキップされる。

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | デフォルト値 | 説明 |
|-------------|-----|-----|-------------|------|
| index.refresh_interval | TimeValue | No | 1s | リフレッシュの実行間隔。-1で無効化 |

### 入力データソース

| データソース | 形式 | 説明 |
|-------------|------|------|
| IndexServiceのシャードマップ | インメモリ | 対象インデックスに属する全シャード |
| Lucene IndexWriter | インメモリ/ディスク | 各シャードのLuceneインデックスライター |

## 出力仕様

### 出力データ

| 出力先 | 形式 | 説明 |
|-------|------|------|
| Lucene IndexReader | インメモリ | 新しいセグメントを含むリーダーが生成される |
| セグメントファイル | ディスクファイル | リフレッシュにより新しいセグメントが作成される場合がある |

### 出力ファイル仕様

| 項目 | 内容 |
|-----|------|
| ファイル名 | Luceneセグメントファイル（_N.si, _N.cfs等） |
| 出力先 | 各シャードのインデックスディレクトリ |
| 文字コード | バイナリ形式 |
| 区切り文字 | 該当なし |

## 処理フロー

### 処理シーケンス

```
1. タイマーによる定期起動
   └─ AbstractAsyncTaskにより指定間隔で起動
2. リフレッシュ間隔チェック
   └─ getRefreshInterval().millis() > 0 を確認
3. シャード走査
   └─ 全シャードをイテレーション
4. リフレッシュ実行
   └─ shard.scheduledRefresh()を呼び出し
5. 次回スケジュール
   └─ mustReschedule()がtrueの場合、再スケジュール
```

### フローチャート

```mermaid
flowchart TD
    A[タイマー起動] --> B{リフレッシュ間隔 > 0?}
    B -->|No| G[処理スキップ]
    B -->|Yes| C[全シャード走査開始]
    C --> D{次のシャードあり?}
    D -->|No| H[処理終了・再スケジュール]
    D -->|Yes| E[shard.scheduledRefresh 実行]
    E --> D
    G --> H
```

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

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

| 処理 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| Luceneリフレッシュ | Luceneセグメント | READ/WRITE | IndexWriterからの新しいリーダーのオープン |

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

#### Luceneセグメント

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| リフレッシュ | IndexReader | 最新のIndexWriterの変更を反映した新しいリーダー | ニアリアルタイム検索の実現 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | IndexShardClosedException | シャードが既にクローズされている | 例外をキャッチして処理を継続 |
| - | AlreadyClosedException | リソースが既にクローズされている | 例外をキャッチして処理を継続 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 明示的なリトライなし（次回スケジュール実行で再試行） |
| リトライ間隔 | index.refresh_interval（デフォルト1秒） |
| リトライ対象エラー | 次回実行時に自動的に再試行 |

### 障害時対応

リフレッシュに失敗した場合、例外がキャッチされ次のシャードの処理に進む。次回スケジュール実行時に再度リフレッシュが試行される。

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

| 項目 | 内容 |
|-----|------|
| トランザクション範囲 | シャード単位（各シャードのリフレッシュは独立） |
| コミットタイミング | リフレッシュ実行時（即時） |
| ロールバック条件 | 該当なし（リフレッシュは冪等操作） |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定処理件数 | インデックス内のシャード数に依存 |
| 目標処理時間 | refresh_interval内に完了すること |
| メモリ使用量上限 | リフレッシュにより新しいセグメントリーダーのメモリが必要 |

## 排他制御

同一インデックスに対するAsyncRefreshTaskは1つのみ存在する。fixedRefreshIntervalSchedulingEnabledが有効な場合、固定間隔でのスケジューリングとなる。各シャードのscheduledRefresh()は内部で適切な同期制御を行う。

## ログ出力

| ログ種別 | 出力タイミング | 出力内容 |
|---------|--------------|---------|
| エラーログ | リフレッシュ失敗時 | シャードクローズ例外等はサイレントにスキップ |

## 監視・アラート

| 監視項目 | 閾値 | アラート先 |
|---------|-----|----------|
| リフレッシュ遅延 | 検索反映の遅延が許容範囲を超える場合 | OpenSearchログ |

## 備考

- 本タスクはREFRESHスレッドプールで実行される
- `index.refresh_interval`を`-1`に設定するとリフレッシュが無効化される
- クラスタレベルのデフォルトリフレッシュ間隔が設定されている場合、インデックスレベルで明示的に設定されていなければクラスタデフォルトが使用される（`clusterDefaultRefreshIntervalSupplier`）
- シャードレベルリフレッシュ（`shardLevelRefreshEnabled`）が有効な場合、本タスクの代わりにAsyncShardRefreshTask（No.8）が使用される
- ソースコード: `server/src/main/java/org/opensearch/index/IndexService.java` (AsyncRefreshTask内部クラス)
