# 通知設計書 3-プロセスI/Oエラー警告

## 概要

本ドキュメントは、JuliaランタイムにおけるプロセスI/Oエラー警告通知の設計を記述する。子プロセスのstdio（標準入出力）とJulia側のIOオブジェクト間でデータ転送中にエラーが発生した場合に警告ログを出力する。

### 本通知の処理概要

**業務上の目的・背景**：Juliaの外部コマンド実行機構では、子プロセスのI/Oストリームとユーザー提供のIOオブジェクトの間でデータを非同期的にコピーする。このデータ転送中にパイプ破損やI/Oエラーが発生する可能性がある。本通知は、そのようなエラーを開発者に警告し、問題の診断を支援する目的で設計されている。

**通知の送信タイミング**：`setup_stdio(stdio::IO, child_readable::Bool)`関数内で生成される非同期タスク（`@async`）において、`write(in, out)`によるデータコピー中に例外が発生した場合に通知される。

**通知の受信者**：Juliaプログラムを実行している開発者。ログメッセージとして標準エラー出力（または設定されたログハンドラ）に出力される。

**通知内容の概要**：「Process I/O error」というメッセージが`@warn`マクロにより出力される。発生した例外とバックトレースが`exception`キーワード引数として付随する。

**期待されるアクション**：開発者はプロセスのI/O設定を確認し、パイプの早期クローズやバッファオーバーフロー、プロセスの異常終了などの原因を調査する。多くの場合、子プロセスが予期せず終了してパイプが破損したことが原因である。

## 通知種別

ログ出力（Warnレベル） - Juliaの`@warn`マクロによるロギングシステム経由の警告通知

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（`@async`タスク内で出力） |
| 優先度 | 中（I/Oエラーはデータ損失の可能性あり） |
| リトライ | 無し |

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

Juliaのロギングフレームワーク（`CoreLogging`）に委譲される。デフォルトでは`stderr`に出力される。

## 通知テンプレート

### メール通知の場合

該当なし（ログ出力のみ）

### 本文テンプレート

```
┌ Warning: Process I/O error
│   exception =
│    IOError: write: broken pipe (EPIPE)
│    Stacktrace:
│     [1] ...
└ @ Base process.jl:323
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| exception | 発生した例外オブジェクトとバックトレースのタプル | `(ex, catch_backtrace())` | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| 非同期タスク | `write(in, out)`実行中の例外発生 | `try-catch`で捕捉された任意の例外 | 子プロセスとの間のI/Oコピータスクでエラーが発生 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| I/Oコピーが正常完了 | エラーが発生しなければ通知されない |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[setup_stdio呼び出し] --> B[PipeEndpoint作成・リンク]
    B --> C["@asyncタスク生成"]
    C --> D["write(in, out) データコピー"]
    D --> E{例外発生?}
    E -->|No| F[close parent]
    E -->|Yes| G["@warn Process I/O error"]
    G --> H[rethrow]
    H --> F
    F --> I[終了]
```

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

### 参照テーブル一覧

該当なし（データベースは使用しない）

### 更新テーブル一覧

該当なし

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| パイプ破損（EPIPE） | 子プロセスが先に終了しパイプが閉じた | 警告出力後、例外を再スローして呼び出し元に通知 |
| IOError | I/O操作中の各種エラー | 警告出力後、例外を再スロー |
| その他の例外 | 予期しないエラー | 警告出力後、例外を再スロー |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0（リトライなし） |
| リトライ間隔 | - |
| リトライ対象エラー | - |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 制限 | なし（エラー発生ごとに出力） |

### 配信時間帯

制限なし（プロセスI/O実行時に出力）

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

例外のバックトレースにファイルパスやコード構造が含まれる。本番環境ではログの出力先管理に注意が必要である。

## 備考

- `@async`タスク内で実行されるため、メインスレッドの処理はブロックされない
- 警告出力後に`rethrow()`されるため、例外は`SyncCloseFD`のタスク結果として伝搬する
- `finally`ブロックで`close(parent)`が必ず実行され、パイプのクリーンアップが保証される

---

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

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

### 推奨読解順序

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

プロセスI/Oに関連するデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | process.jl | `base/process.jl` | `Process`構造体（3-21行目）の`in`、`out`、`err`フィールド |
| 1-2 | process.jl | `base/process.jl` | `SyncCloseFD`構造体（42-45行目）- 子プロセスのFDと同期用Taskのペア |
| 1-3 | process.jl | `base/process.jl` | `SpawnIO`型エイリアス（87行目）と`SpawnIOs`（88行目） |

**読解のコツ**: `SyncCloseFD`は子プロセスのファイルディスクリプタと、I/Oコピーの完了を待つための`Task`を保持する軽量構造体である。

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

通知が発生する`setup_stdio`関数を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | process.jl | `base/process.jl` | `setup_stdio(stdio::IO, child_readable::Bool)`関数（306-334行目） |

**主要処理フロー**:
1. **307行目**: `PipeEndpoint()`で親側のパイプエンドポイントを作成
2. **308行目**: `link_pipe()`で読み書きペアを生成
3. **310行目**: `open_pipe!()`で親パイプを開く
4. **318-319行目**: `in`と`out`を`child_readable`に応じて設定
5. **320-324行目**: `@async`タスクで`write(in, out)`を実行し、例外時に`@warn "Process I/O error"`を出力
6. **326行目**: `close(parent)`を`finally`で確実に実行
7. **328行目**: `SyncCloseFD(child, t)`を返す

#### Step 3: 呼び出し元を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | process.jl | `base/process.jl` | `setup_stdios`関数（236-251行目） - 全stdioのセットアップを統括 |
| 3-2 | process.jl | `base/process.jl` | `_spawn`関数（155-160行目） - プロセス生成のエントリーポイント |

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

```
run(`cmd`) / open(`cmd`)
    |
    +-- _spawn(cmd, stdios)  [base/process.jl:155]
        |
        +-- setup_stdios(f, stdios)  [base/process.jl:236]
            |
            +-- setup_stdio(stdio::IO, child_readable)  [base/process.jl:306]
                |
                +-- PipeEndpoint() + link_pipe()
                +-- @async write(in, out)  [base/process.jl:320]
                    |
                    +-- (例外時) @warn "Process I/O error"  [base/process.jl:323]
                    +-- (finally) close(parent)  [base/process.jl:326]
```

### データフロー図

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

ユーザーIOオブジェクト ──> setup_stdio                  ──> SyncCloseFD
                          |                                (child FD + Task)
                          +-- @async write(in, out)
                              |
                              +-- (正常) データコピー完了
                              +-- (異常) @warn ログ出力 ──> stderr
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| process.jl | `base/process.jl` | ソース | プロセス管理とstdioセットアップの全実装 |
| cmd.jl | `base/cmd.jl` | ソース | コマンドとリダイレクトの型定義 |
| stream.jl | `base/stream.jl` | ソース | PipeEndpoint等のIO型定義 |
