# 通知設計書 6-HTTPクライアントリクエスト通知

## 概要

本ドキュメントは、Node.jsのHTTPクライアントモジュールにおける診断チャンネル通知機能の設計書である。

### 本通知の処理概要

HTTPクライアントリクエスト通知は、Node.jsアプリケーションがHTTPリクエストを発行する際の各フェーズ（作成・開始・エラー・完了）で診断チャンネルに通知を送信する機能を提供する。これにより、HTTPクライアントの動作を外部から監視・計装することが可能となる。

**業務上の目的・背景**：分散システムにおいて、外部APIやマイクロサービスへのHTTPリクエストの監視は重要である。リクエストの遅延、エラー率、スループットなどのメトリクスを収集し、システム全体の健全性を把握する必要がある。HTTPクライアント通知は、アプリケーションコードを変更せずにこれらの情報を収集する標準的な方法を提供する。

**通知の送信タイミング**：
- http.client.request.created: ClientRequestオブジェクト作成時
- http.client.request.start: リクエストデータ送信開始時
- http.client.request.error: リクエストエラー発生時
- http.client.response.finish: レスポンス受信完了時

**通知の受信者**：各診断チャンネルに対してsubscribe()で登録したコールバック関数。APMツール、トレーシングライブラリ、カスタム監視コードなどが想定される。

**通知内容の概要**：リクエストオブジェクト、レスポンスオブジェクト、エラーオブジェクトなど、HTTPリクエストの状態に関する情報。

**期待されるアクション**：購読者は受信したデータを使用して、リクエストのトレーシング、メトリクス収集、ログ出力などを行う。

## 通知種別

内部イベント通知（diagnostics_channel）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期 |
| 優先度 | 高（パフォーマンスクリティカル） |
| リトライ | なし（同期実行のため） |

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

各チャンネルに対してsubscribe()を呼び出した購読者に送信される。hasSubscribersで事前チェックを行い、購読者がいない場合はpublish()をスキップしてパフォーマンスオーバーヘッドを最小化。

## 通知テンプレート

### チャンネル一覧

| チャンネル名 | タイミング | 説明 |
|-------------|---------|------|
| http.client.request.created | ClientRequest作成時 | リクエストオブジェクトの初期化完了時に発火 |
| http.client.request.start | リクエスト開始時 | _finish()メソッド内でデータ送信開始時に発火 |
| http.client.request.error | エラー発生時 | emitErrorEvent()呼び出し時に発火 |
| http.client.response.finish | レスポンス完了時 | parserOnIncomingClient()内でレスポンス受信時に発火 |

### データ構造

```javascript
// http.client.request.created
{
  request: ClientRequest  // HTTPリクエストオブジェクト
}

// http.client.request.start
{
  request: ClientRequest  // HTTPリクエストオブジェクト
}

// http.client.request.error
{
  request: ClientRequest,  // HTTPリクエストオブジェクト
  error: Error            // エラーオブジェクト
}

// http.client.response.finish
{
  request: ClientRequest,  // HTTPリクエストオブジェクト
  response: IncomingMessage  // HTTPレスポンスオブジェクト
}
```

### 添付ファイル

該当なし（プログラム内部通知のため）

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| request | HTTPリクエストオブジェクト | ClientRequestインスタンス | Yes |
| response | HTTPレスポンスオブジェクト | IncomingMessageインスタンス | 一部 |
| error | エラーオブジェクト | Errorインスタンス | 一部 |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| ClientRequest作成 | new ClientRequest() | hasSubscribers == true | コンストラクタ完了時 |
| リクエスト開始 | ClientRequest._finish() | hasSubscribers == true | リクエストデータ送信開始時 |
| エラー発生 | emitErrorEvent() | hasSubscribers == true | エラー発生時 |
| レスポンス完了 | parserOnIncomingClient() | hasSubscribers == true | ステータスコード受信後 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| 購読者なし | hasSubscribersがfalseの場合、publish()をスキップ |
| 情報レスポンス | 100-199ステータスコード（101除く）ではresponse.finishは発火しない |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[http.request/https.request呼び出し] --> B[ClientRequestコンストラクタ]
    B --> C{hasSubscribers?}
    C -->|Yes| D[http.client.request.created発火]
    C -->|No| E[スキップ]
    D --> F[ソケット接続]
    E --> F
    F --> G[_finish呼び出し]
    G --> H{hasSubscribers?}
    H -->|Yes| I[http.client.request.start発火]
    H -->|No| J[スキップ]
    I --> K[レスポンス待機]
    J --> K
    K --> L{結果}
    L -->|エラー| M[emitErrorEvent]
    M --> N{hasSubscribers?}
    N -->|Yes| O[http.client.request.error発火]
    N -->|No| P[スキップ]
    L -->|成功| Q[parserOnIncomingClient]
    Q --> R{hasSubscribers?}
    R -->|Yes| S[http.client.response.finish発火]
    R -->|No| T[スキップ]
```

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

### 参照テーブル一覧

本通知はデータベースを使用しない。

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| なし | - | メモリ内オブジェクトのみ使用 |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| なし | - | データベース更新なし |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 接続エラー | ネットワーク接続失敗 | http.client.request.errorチャンネルに通知後、errorイベント発火 |
| タイムアウト | リクエストタイムアウト | http.client.request.errorチャンネルに通知後、errorイベント発火 |
| パースエラー | レスポンス解析失敗 | http.client.request.errorチャンネルに通知後、errorイベント発火 |
| ソケットハングアップ | 接続が予期せず切断 | ConnResetExceptionでhttp.client.request.error通知 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | なし（通知自体にはリトライなし） |
| リトライ間隔 | なし |
| リトライ対象エラー | なし |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | なし（制限なし） |
| 1日あたり上限 | なし |

### 配信時間帯

制限なし（プログラム実行中は常時利用可能）

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

- リクエストオブジェクトには認証ヘッダー（Authorization等）が含まれる可能性があるため、購読者はログ出力時に機密情報をマスクすべき
- レスポンスボディに機密データが含まれる場合があるため、適切な取り扱いが必要
- 購読者のパフォーマンスがHTTPリクエスト全体のパフォーマンスに影響するため、軽量な処理を心がける

## 備考

- Node.js v18.1.0でhttp.client.request.createdが追加
- Node.js v18.17.0でhttp.client.request.start/error、http.client.response.finishが追加
- hasSubscribersチェックにより、購読者がいない場合のオーバーヘッドは最小限
- パフォーマンス監視（PerformanceObserver）との併用も可能

---

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

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

### 推奨読解順序

#### Step 1: チャンネル定義を理解する

まず、診断チャンネルの定義箇所を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | _http_client.js | `lib/_http_client.js` | 95-99行目：4つの診断チャンネルの定義 |

**読解のコツ**: dc.channel()で作成されるチャンネル名のパターンを確認する。

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

ClientRequestの作成とチャンネル通知の流れを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | _http_client.js | `lib/_http_client.js` | 191-445行目：ClientRequestコンストラクタ |

**主要処理フロー**:
1. **191行目**: ClientRequest関数の開始
2. **440-444行目**: request.created通知の発火
3. **403-404行目**: agent.addRequest()またはソケット接続

#### Step 3: 各通知ポイントを理解する

各診断チャンネルへの通知箇所を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | _http_client.js | `lib/_http_client.js` | 449-473行目：ClientRequest._finish()内のrequest.start通知 |
| 3-2 | _http_client.js | `lib/_http_client.js` | 101-109行目：emitErrorEvent()内のrequest.error通知 |
| 3-3 | _http_client.js | `lib/_http_client.js` | 757-762行目：parserOnIncomingClient()内のresponse.finish通知 |

**主要処理フロー（_finish）**:
- **464-468行目**: hasSubscribersチェックとrequest.start通知

**主要処理フロー（emitErrorEvent）**:
- **102-107行目**: hasSubscribersチェックとrequest.error通知

**主要処理フロー（parserOnIncomingClient）**:
- **757-762行目**: hasSubscribersチェックとresponse.finish通知

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

```
http.request() / https.request()
    │
    └─ new ClientRequest() [191行目]
           │
           ├─ 各種オプション処理
           │
           ├─ agent.addRequest() [403行目]
           │
           └─ onClientRequestCreatedChannel.publish() [440-444行目]
                  └─ { request: this }

ClientRequest._finish() [449行目]
    │
    └─ onClientRequestStartChannel.publish() [464-468行目]
           └─ { request: this }

emitErrorEvent() [101行目]
    │
    ├─ onClientRequestErrorChannel.publish() [102-107行目]
    │      └─ { request, error }
    │
    └─ request.emit('error', error) [108行目]

parserOnIncomingClient() [686行目]
    │
    └─ onClientResponseFinishChannel.publish() [757-762行目]
           └─ { request: req, response: res }
```

### データフロー図

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

http.request()      ClientRequest              診断チャンネル購読者
    │                    │                            │
    ▼                    ▼                            ▼
options ──────▶ new ClientRequest() ──────▶ request.created
    │                    │                            │
    │                    ▼                            ▼
    │              _finish() ─────────────────▶ request.start
    │                    │                            │
    │                    ▼                            ▼
    │              [エラー発生] ──────────────▶ request.error
    │                    │                            │
    │                    ▼                            ▼
    └─────────▶ [レスポンス受信] ─────────▶ response.finish
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| _http_client.js | `lib/_http_client.js` | ソース | HTTPクライアント実装、診断チャンネル通知 |
| diagnostics_channel.js | `lib/diagnostics_channel.js` | ソース | diagnostics_channelモジュール |
| _http_common.js | `lib/_http_common.js` | ソース | HTTP共通処理 |
| _http_agent.js | `lib/_http_agent.js` | ソース | HTTPエージェント |
