# 機能設計書 28-Reloader

## 概要

本ドキュメントは、Ruby on Railsのコードリロード機能の設計仕様を定義する。Reloaderは、開発環境でソースコードの変更を検出し、アプリケーションを再起動せずにコードを再読み込みする機能である。

### 本機能の処理概要

**業務上の目的・背景**：開発中のWebアプリケーションでは、コード変更の確認のためにサーバーを再起動するのは非効率である。Reloader機能は、ファイルシステムの変更を監視し、リクエストごとに変更されたコードを自動的に再読み込みすることで、開発サイクルを大幅に短縮する。Zeitwerkオートローダーと連携して、変更されたクラスのアンロードと再ロードを実現する。

**機能の利用シーン**：開発環境でのコード変更時に自動的に動作する。モデル、コントローラ、ビュー、ヘルパー、メーラー等のRubyファイルが変更された際に、次のリクエストで変更が反映される。

**主要な処理内容**：
1. ファイル変更の検出（ファイル監視）
2. クラスのアンロード（定数の削除）
3. コードの再読み込み（require_dependency / Zeitwerk）
4. コールバック実行（to_prepare、to_run、to_complete）
5. 依存関係のインターロック管理

**関連システム・外部連携**：Zeitwerk（オートローダー）、ActiveSupport::Dependencies（依存関係管理）、ActiveSupport::FileUpdateChecker（ファイル監視）と連携する。

**権限による制御**：開発環境でのみデフォルト有効。config.cache_classes = false で有効化。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | 任意の画面 | 補助機能 | コード変更の自動反映 |

## 機能種別

開発支援 / ミドルウェア

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| check | Proc | No | リロード必要性をチェックするProc | trueを返す場合にリロード |
| executor | Class | No | 実行コンテキストを管理するクラス | デフォルトはActiveSupport::Executor |

### 入力データソース

- ファイルシステム（変更検出）
- アプリケーション設定（config.reload_classes_only_on_change等）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| リロード結果 | Boolean | リロードが実行されたかどうか |

### 出力先

- アプリケーションの定数空間（クラス再定義）
- ログファイル（リロード情報）

## 処理フロー

### 処理シーケンス

```
1. リクエスト到着（ActionDispatch::Reloader ミドルウェア）
   └─ ActiveSupport::Reloader.run!
2. リロードチェック
   └─ check.call でファイル変更を確認
3. 変更あり時のリロード処理
   └─ before_class_unload コールバック
   └─ クラスのアンロード
   └─ after_class_unload コールバック
   └─ to_run コールバック
4. アプリケーション処理
   └─ 必要なクラスをオートロード
5. リクエスト完了
   └─ to_complete コールバック
   └─ reloaded! でフラグリセット
```

### フローチャート

```mermaid
flowchart TD
    A[リクエスト到着] --> B[Reloader.run!]
    B --> C{check.call}
    C -->|変更なし| D[Null返却]
    C -->|変更あり| E[リロード処理開始]
    E --> F[before_class_unload]
    F --> G[クラスアンロード]
    G --> H[after_class_unload]
    H --> I[to_run コールバック]
    I --> J[to_prepare コールバック]
    J --> K[アプリケーション処理]
    D --> K
    K --> L[to_complete コールバック]
    L --> M[reloaded!]
    M --> N[レスポンス返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-28-01 | 変更検出 | reload_classes_only_on_change=true で変更時のみリロード | デフォルト動作 |
| BR-28-02 | インターロック | クラスアンロード中は他スレッドをブロック | マルチスレッド環境 |
| BR-28-03 | to_prepare実行 | アプリ起動時とリロード後に実行 | 初期化処理用 |
| BR-28-04 | Null Object | リロード不要時はNullを返却 | checkがfalse時 |

### 計算ロジック

リロード判定：
```ruby
# checkプロックがtrueを返す場合のみリロード
def self.check!
  @should_reload ||= check.call
end
```

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| - | - | - | データベース操作なし |

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

本機能はデータベースを直接操作しない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| NameError | LoadError | クラス定義が不正 | コードを修正して再リクエスト |
| SyntaxError | ParseError | Rubyの構文エラー | コードを修正して再リクエスト |

### リトライ仕様

コードエラー時は例外が発生し、開発者がコードを修正後に再リクエストが必要。

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

本機能はデータベーストランザクションを使用しない。

## パフォーマンス要件

- ファイル変更検出は効率的に実施（mtime比較）
- 変更がない場合はリロード処理をスキップ
- 本番環境では無効化（config.cache_classes = true）

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

- 本番環境ではコードリロードを無効化すること
- ファイル監視のパスを信頼できるディレクトリに限定

## 備考

- Zeitwerkがデフォルトのオートローダー
- ActiveSupport::Dependencies.interposeで低レベル制御可能
- config.file_watcherでカスタムファイル監視を設定可能

---

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

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

### 推奨読解順序

#### Step 1: ActiveSupport::Reloaderの基本構造を理解する

コアとなるReloaderクラスを確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | reloader.rb | `activesupport/lib/active_support/reloader.rb` | Reloaderクラス、コールバック定義、リロードフロー |

**読解のコツ**: ReloaderはExecutionWrapperを継承し、コールバック（prepare、class_unload）を追加している。

**主要処理フロー**:
- **28-31行目**: define_callbacks で prepare、class_unload コールバックを定義
- **34-36行目**: to_prepare でprepareコールバックを登録
- **39-41行目**: before_class_unload でclass_unloadのbeforeコールバックを登録
- **44-46行目**: after_class_unload でclass_unloadのafterコールバックを登録
- **51-60行目**: reload! で手動リロードを実行
- **62-68行目**: run! でリロード必要性をチェック
- **71-82行目**: wrap でリクエストをラップして実行

#### Step 2: ActionDispatch::Reloaderミドルウェアを理解する

Rackミドルウェアとしての統合を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | reloader.rb | `actionpack/lib/action_dispatch/middleware/reloader.rb` | Executorを継承したシンプルな実装 |

**読解のコツ**: ActionDispatch::ReloaderはActionDispatch::Executorを継承しただけのシンプルなクラス。実際の処理はActiveSupportのReloader/Executorで行われる。

**主要処理フロー**:
- **14行目**: Executor を継承

#### Step 3: インターロック管理を理解する

マルチスレッド環境でのロック管理を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | reloader.rb | `activesupport/lib/active_support/reloader.rb` | require_unload_lock!、release_unload_lock! |

**主要処理フロー**:
- **106-111行目**: require_unload_lock! でアンロードロックを取得
- **114-119行目**: release_unload_lock! でロックを解放
- **126-129行目**: class_unload! でロックを取得してコールバック実行

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

```
Rack ミドルウェアスタック
    │
    ├─ ActionDispatch::Reloader (Executor を継承)
    │      │
    │      └─ ActionDispatch::Executor#call
    │             │
    │             └─ ActiveSupport::Reloader.wrap
    │                    │
    │                    ├─ run! (62行目)
    │                    │      │
    │                    │      └─ check! (87-89行目)
    │                    │             └─ check.call
    │                    │
    │                    └─ complete! (131行目)
    │                           └─ reloaded! (91-93行目)
    │
    └─ リロード処理
           │
           ├─ class_unload! (126行目)
           │      ├─ require_unload_lock! (106行目)
           │      └─ run_callbacks(:class_unload)
           │
           └─ prepare! (95-97行目)
                  └─ run_callbacks(:prepare)
```

### データフロー図

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

ファイルシステム ───▶ ファイル監視 ───▶ 変更検出結果
      │                    │
      │                    ▼
      │              ┌─────────────────┐
      │              │ check! メソッド │
      │              │ (87-89行目)     │───▶ Boolean
      │              └─────────────────┘
      │                    │
      │                    ▼
      │              ┌─────────────────┐
      │              │ クラスアンロード │
      │              │ (class_unload)  │───▶ 定数削除
      │              └─────────────────┘
      │                    │
      │                    ▼
リクエスト ───▶ オートロード ───▶ クラス再定義
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| reloader.rb | `activesupport/lib/active_support/reloader.rb` | ソース | コアReloaderクラス |
| reloader.rb | `actionpack/lib/action_dispatch/middleware/reloader.rb` | ソース | Rackミドルウェア |
| executor.rb | `actionpack/lib/action_dispatch/middleware/executor.rb` | ソース | Executorミドルウェア |
| execution_wrapper.rb | `activesupport/lib/active_support/execution_wrapper.rb` | ソース | 実行ラッパー基底クラス |
| dependencies.rb | `activesupport/lib/active_support/dependencies.rb` | ソース | 依存関係管理 |
| file_update_checker.rb | `activesupport/lib/active_support/file_update_checker.rb` | ソース | ファイル変更検出 |
