# バッチ設計書 8-AsyncShardRefreshTask

## 概要

本ドキュメントは、OpenSearchのIndexShardにおけるシャード単位の独立したリフレッシュを定期的に実行するバッチタスクの設計を記載する。

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

AsyncShardRefreshTaskは、シャード単位で独立してリフレッシュ（Luceneリーダーの更新）を定期的に実行するExperimental機能のバッチタスクである。インデックスレベルのAsyncRefreshTask（No.2）の代替として、シャードごとに独立したリフレッシュスケジューリングを提供する。

**業務上の目的・背景**：インデックスレベルのリフレッシュ（AsyncRefreshTask）では、すべてのシャードが同一タイミングでリフレッシュされるため、大量のシャードを持つインデックスでリフレッシュの負荷が集中する可能性がある。シャードレベルのリフレッシュにより、各シャードが独立したタイミングでリフレッシュを実行でき、負荷の分散とより細かな制御が可能になる。

**バッチの実行タイミング**：リフレッシュ間隔（`index.refresh_interval`）に基づいて各シャードで独立して定期実行される。`shardLevelRefreshEnabled`が有効な場合にのみ使用される。固定間隔スケジューリングに対応。

**主要な処理内容**：
1. 当該シャードに対して`scheduledRefresh()`を呼び出す
2. LuceneのIndexReaderが更新され、新しいドキュメントが検索可能になる

**前後の処理との関連**：AsyncRefreshTask（No.2）の代替機能であり、両者は排他的に動作する。shardLevelRefreshEnabledが有効な場合は本タスク、無効な場合はAsyncRefreshTaskが使用される。

**影響範囲**：当該シャードのLuceneリーダーが更新される。個別シャードの検索可能データの鮮度に影響する。

## バッチ種別

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

## 実行スケジュール

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

## 実行条件

### 前提条件

| 条件 | 説明 |
|-----|------|
| シャードがCLOSED以外 | `indexShard.state != IndexShardState.CLOSED`であること |
| インデックスがOPEN状態 | `IndexMetadata.State.OPEN`であること |
| シャードレベルリフレッシュ有効 | `shardLevelRefreshEnabled`がtrueであること |

### 実行可否判定

`mustReschedule()`でシャードがCLOSED状態でないこと、インデックスがOPEN状態であることを確認する。`startRefreshTask()`により明示的に開始され、`stopRefreshTask()`により停止される。

## 入力仕様

### 入力パラメータ

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

### 入力データソース

| データソース | 形式 | 説明 |
|-------------|------|------|
| IndexShard | インメモリ | 対象シャードのエンジン |
| Lucene IndexWriter | インメモリ/ディスク | シャードのLuceneインデックスライター |

## 出力仕様

### 出力データ

| 出力先 | 形式 | 説明 |
|-------|------|------|
| Lucene IndexReader | インメモリ | 新しいセグメントを含むリーダーが生成される |

### 出力ファイル仕様

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

## 処理フロー

### 処理シーケンス

```
1. タイマーによる定期起動
   └─ AbstractAsyncTaskにより指定間隔で起動
2. リフレッシュ実行
   └─ indexShard.scheduledRefresh()を呼び出し
3. 次回スケジュール
   └─ mustReschedule()がtrueの場合、再スケジュール
```

### フローチャート

```mermaid
flowchart TD
    A[タイマー起動] --> B[indexShard.scheduledRefresh 実行]
    B --> C{mustReschedule?}
    C -->|Yes| A
    C -->|No| D[タスク終了]
```

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

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

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

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

#### Luceneセグメント

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| リフレッシュ | IndexReader | 最新のIndexWriterの変更を反映した新しいリーダー | シャード単位の独立リフレッシュ |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 各種Exception | リフレッシュ実行時のエラー | AbstractAsyncTaskのエラーハンドリングにより処理 |

### リトライ仕様

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

### 障害時対応

リフレッシュに失敗した場合、次回スケジュール実行時に再度リフレッシュが試行される。

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

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

## パフォーマンス要件

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

## 排他制御

各シャードに対してAsyncShardRefreshTaskは1つのみ存在する。`startRefreshTask()`と`stopRefreshTask()`はrefreshMutexによる排他制御下で呼ばれる。

## ログ出力

| ログ種別 | 出力タイミング | 出力内容 |
|---------|--------------|---------|
| エラーログ | リフレッシュ失敗時 | AbstractAsyncTaskによるエラーログ |

## 監視・アラート

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

## 備考

- 本タスクはREFRESHスレッドプールで実行される
- `@ExperimentalApi`アノテーションが付与されており、Experimental機能である
- IndexShard内の内部クラスとして実装されている（IndexServiceの他タスクとは異なる）
- `startRefreshTask()`で開始、`stopRefreshTask()`で停止という明示的なライフサイクル管理が行われる
- ソースコード: `server/src/main/java/org/opensearch/index/shard/IndexShard.java` (AsyncShardRefreshTask内部クラス)
