# 機能設計書 29-Live Streaming

## 概要

本ドキュメントは、Ruby on Railsのライブストリーミング機能の設計仕様を定義する。Live Streamingは、Server-Sent Events（SSE）を使用してサーバーからクライアントへリアルタイムにデータを配信する機能である。

### 本機能の処理概要

**業務上の目的・背景**：Webアプリケーションにおいて、サーバー側で発生するイベントをリアルタイムでクライアントに通知したい場合がある。Live Streamingは、HTTPコネクションを維持したまま、サーバーからクライアントへ継続的にデータを送信することで、ポーリングなしでリアルタイム更新を実現する。Action Cableより軽量で、単方向通信で十分な場合に適している。

**機能の利用シーン**：ライブフィード、進捗状況の表示、リアルタイム通知、ログストリーミング、株価更新など、サーバーからクライアントへの一方向リアルタイム通信が必要な場面で使用する。

**主要な処理内容**：
1. ActionController::Liveモジュールのinclude
2. レスポンスストリームへのデータ書き込み
3. Server-Sent Events（SSE）フォーマットでの送信
4. 別スレッドでのアクション実行
5. クライアント切断の検出とストリームクローズ

**関連システム・外部連携**：Rack（HTTPストリーミング）、ブラウザ（EventSource API）、Concurrent-Ruby（スレッドプール）と連携する。

**権限による制御**：特になし。認証が必要な場合はコントローラのbefore_actionで制御。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | リアルタイム更新画面 | 主機能 | Server-Sent Eventsによるリアルタイムデータ配信 |

## 機能種別

リアルタイム通信 / ストリーミング

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| stream | ActionController::Live::Buffer | Yes | 出力ストリームオブジェクト | - |
| options[:event] | String | No | SSEイベント名 | - |
| options[:retry] | Integer | No | 再接続待機時間（ミリ秒） | 正の整数 |
| options[:id] | String | No | イベントID | - |

### 入力データソース

- コントローラアクション内での response.stream 呼び出し
- アプリケーションロジックからのデータ

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| SSEデータ | String | Server-Sent Events形式のテキストストリーム |

### 出力先

- HTTPレスポンスボディ（チャンクエンコーディング）
- ブラウザのEventSource API

## 処理フロー

### 処理シーケンス

```
1. リクエスト到着
   └─ コントローラアクション開始
2. 別スレッドでアクション実行
   └─ new_controller_thread でスレッド生成
   └─ スレッドローカル変数のコピー
3. ストリーミング開始
   └─ response.stream への書き込み
   └─ SSE.write でフォーマット変換
4. データ送信ループ
   └─ stream.write でデータ送信
   └─ クライアント切断チェック
5. ストリーム終了
   └─ stream.close
   └─ スレッドクリーンアップ
```

### フローチャート

```mermaid
flowchart TD
    A[リクエスト到着] --> B[Liveモジュールinclude確認]
    B --> C[新スレッドでアクション実行]
    C --> D[スレッドローカル変数コピー]
    D --> E[response.stream取得]
    E --> F[Content-Type設定]
    F --> G{データあり?}
    G -->|Yes| H[stream.write]
    H --> I{クライアント接続中?}
    I -->|Yes| G
    I -->|No| J[ClientDisconnected]
    G -->|No| K[stream.close]
    J --> K
    K --> L[スレッドクリーンアップ]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-29-01 | 別スレッド実行 | アクションは別スレッドで実行 | Liveモジュールinclude時 |
| BR-29-02 | ストリームクローズ必須 | アクション終了時にstream.closeを呼ぶ | 必須 |
| BR-29-03 | ヘッダー先行送信 | 最初のwrite時にヘッダーがコミット | ヘッダー変更不可 |
| BR-29-04 | SSEフォーマット | event:, data:, id:, retry: フィールド | SSE使用時 |

### 計算ロジック

SSEメッセージフォーマット：
```
event: event-name
id: 10
retry: 300
data: {"key":"value"}

```

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| - | - | - | アプリケーションロジックによる |

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

Live Streaming自体はデータベース操作を行わない。ストリーミング中のデータ取得はアプリケーションロジックに依存する。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| ClientDisconnected | RuntimeError | クライアントが接続を切断 | ストリームをクローズ |
| IOError | IOError | ストリーム書き込みエラー | ストリームをクローズ |

### リトライ仕様

クライアント切断時、ブラウザのEventSource APIが自動的に再接続を試みる。retry フィールドで待機時間を指定可能。

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

本機能はデータベーストランザクションを使用しない。別スレッドで実行されるため、親スレッドのトランザクションは継承されない。

## パフォーマンス要件

- 各ストリームに1スレッド消費
- Concurrent::CachedThreadPool で管理
- Buffer.queue_size でキューサイズを制御（デフォルト10）
- 同時接続数に注意

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

- 認証が必要な場合はbefore_actionで制御
- クロスオリジン制限（CORS）を適切に設定
- レート制限の実装を検討

## 備考

- HTTP/1.0クライアントには非対応（通常のレスポンスを返す）
- Rack::ETagミドルウェアはストリーミングをバッファリングする可能性あり
- Last-ModifiedまたはETagヘッダーを設定して回避可能
- send_streamメソッドでファイルストリーミングも可能

---

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

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

### 推奨読解順序

#### Step 1: Liveモジュールの基本構造を理解する

ActionController::Liveモジュールのエントリーポイントを確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | live.rb | `actionpack/lib/action_controller/metal/live.rb` | Liveモジュール、SSEクラス、Bufferクラス |

**読解のコツ**: Liveモジュールをincludeすると、processメソッドがオーバーライドされ、アクションが別スレッドで実行されるようになる。

**主要処理フロー**:
- **91-98行目**: Liveモジュールのincluded
- **153-188行目**: SSEクラスでServer-Sent Eventsフォーマット
- **193-289行目**: Bufferクラスでストリーム管理
- **307-350行目**: processメソッドで別スレッド実行

#### Step 2: SSEクラスを理解する

Server-Sent Eventsのフォーマット処理を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | live.rb | `actionpack/lib/action_controller/metal/live.rb` | SSEクラスのwrite、perform_write |

**主要処理フロー**:
- **154行目**: PERMITTED_OPTIONS でevent, id, retry を定義
- **165-172行目**: write でJSONエンコードとフォーマット
- **175-187行目**: perform_write でSSEフォーマット生成

#### Step 3: Bufferクラスを理解する

ストリームバッファの管理を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | live.rb | `actionpack/lib/action_controller/metal/live.rb` | Bufferクラス、write、close、abort |

**主要処理フロー**:
- **196-199行目**: queue_size設定（デフォルト10）
- **208-214行目**: initialize でキューとモニター初期化
- **216-233行目**: write でデータ書き込みとクライアント切断チェック
- **244-250行目**: close でストリーム終了
- **256-261行目**: abort でクライアント切断処理

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

```
Controller Action
    │
    └─ include ActionController::Live
           │
           ├─ process (307行目)
           │      │
           │      ├─ new_controller_thread (404行目)
           │      │      └─ live_thread_pool_executor.post
           │      │
           │      ├─ IsolatedExecutionState.share_with (323行目)
           │      │
           │      └─ super(name) (324行目)
           │             └─ アクション実行
           │
           └─ response.stream
                  │
                  ├─ Live::Buffer#write (216行目)
                  │      └─ @buf.push (222行目)
                  │
                  └─ Live::SSE#write (165行目)
                         └─ perform_write (168, 170行目)
                                └─ @stream.write (186行目)
```

### データフロー図

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

アプリケーションデータ ───▶ SSE.write ───▶ SSEフォーマット
      │                    │
      │                    ▼
      │              ┌─────────────────┐
      │              │ Buffer (キュー) │
      │              │ SizedQueue(10) │───▶ チャンクデータ
      │              └─────────────────┘
      │                    │
      │                    ▼
HTTPレスポンス ◀───────────▶ Rack チャンクエンコーディング
      │                    │
      │                    ▼
      └──────────────▶ ブラウザ EventSource API
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| live.rb | `actionpack/lib/action_controller/metal/live.rb` | ソース | Liveモジュール本体 |
| response.rb | `actionpack/lib/action_dispatch/http/response.rb` | ソース | HTTPレスポンスクラス |
| isolated_execution_state.rb | `activesupport/lib/active_support/isolated_execution_state.rb` | ソース | スレッド状態管理 |
| concurrent_ruby | 外部gem | ライブラリ | スレッドプール管理 |
