# 機能設計書 1-Semaphore

## 概要

本ドキュメントは、Hack Standard Library (HSL) の非同期処理モジュール `HH\Lib\Async\Semaphore` クラスの機能設計書である。

### 本機能の処理概要

**業務上の目的・背景**：
非同期プログラミングにおいて、大量の並行処理を同時に実行すると、リソース（メモリ、CPU、外部API接続数など）を過剰に消費し、システムの安定性に影響を与える可能性がある。Semaphoreは、同時実行数を制限することで、リソースの枯渇を防ぎ、安定した非同期処理を実現するための機能である。データベース接続プールや外部APIの同時リクエスト数制限など、実務上多くの場面で必要とされる機能である。

**機能の利用シーン**：
- 外部APIへのリクエストを同時に最大N件に制限したい場合
- データベース接続数を一定数以下に抑えたい場合
- ファイル処理やネットワーク処理の並行度を制御したい場合
- バッチ処理で処理速度とリソース消費のバランスを取りたい場合

**主要な処理内容**：
1. 同時実行数の上限を指定してSemaphoreインスタンスを作成
2. `waitForAsync()`メソッドで処理を実行キューに追加
3. 同時実行数が上限に達している場合、内部のConditionを使用して待機
4. 実行スロットが空くと、待機中のタスクが順番に実行される
5. タスク完了後、次の待機タスクに通知を送信

**関連システム・外部連携**：
- `HH\Lib\Async\Condition`クラスを内部的に使用して待機制御を実現
- `AwaitAllWaitHandle`を使用して非同期処理の追跡を行う

**権限による制御**：該当なし（ライブラリ機能のため）

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | 画面なし | - | 本プロジェクトはUIを持たないライブラリのため該当なし |

## 機能種別

並行処理制御 / リソース管理

## 入力仕様

### 入力パラメータ

#### コンストラクタ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| concurrentLimit | int | Yes | 同時実行数の上限 | 1以上の整数であること |
| f | (function(Tin): Awaitable&lt;Tout&gt;) | Yes | 各入力に対して実行する非同期関数 | callable |

#### waitForAsync()メソッド

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| value | Tin | Yes | 処理関数に渡す入力値 | 型パラメータTinに適合 |

### 入力データソース

- プログラムから直接呼び出し（API）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 戻り値 | Awaitable&lt;Tout&gt; | 処理関数の実行結果を含むAwaitable |

### 出力先

- 呼び出し元プログラムへの戻り値

## 処理フロー

### 処理シーケンス

```
1. waitForAsync()が呼び出される
   └─ 入力値を受け取り、非同期処理を開始
2. 同時実行数のチェック
   └─ runningCount + recentOpenCount >= concurrentLimit を評価
3. 上限に達している場合
   └─ 新しいConditionを作成しblocking dictに追加
   └─ waitForNotificationAsync()で通知を待機
4. 実行スロットを確保
   └─ runningCountをインクリメント
5. 処理関数を実行
   └─ $f($value)をawaitして結果を取得
6. 完了処理（finally節）
   └─ runningCountをデクリメント
   └─ blockingキューの先頭タスクに通知を送信
7. 結果を返却
```

### フローチャート

```mermaid
flowchart TD
    A[waitForAsync開始] --> B{同時実行数 >= 上限?}
    B -->|Yes| C[Conditionを作成してblockingに追加]
    C --> D[waitForNotificationAsync]
    D --> E[通知受信]
    E --> F[recentOpenCountをデクリメント]
    F --> G[runningCountをインクリメント]
    B -->|No| G
    G --> H[処理関数を実行]
    H --> I[finally: runningCountをデクリメント]
    I --> J{待機中タスクあり?}
    J -->|Yes| K[次のタスクに通知]
    K --> L[recentOpenCountをインクリメント]
    L --> M[結果を返却]
    J -->|No| M
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 同時実行数制限 | concurrentLimitで指定した数を超える同時実行は行わない | 常時 |
| BR-02 | FIFO順序保証 | 待機キューはFIFO（先入れ先出し）で処理される | 複数タスクが待機中の場合 |
| BR-03 | 例外伝播 | 処理関数で発生した例外は呼び出し元に伝播する | 処理関数が例外をスロー |
| BR-04 | インスタンス独立性 | 同時実行数制限はインスタンス単位で適用される | 複数Semaphoreインスタンスが存在する場合 |

### 計算ロジック

**待機判定式**：
```
待機が必要 = (runningCount + recentOpenCount >= concurrentLimit)
```

- `runningCount`: 現在実行中のタスク数
- `recentOpenCount`: 通知済みだがまだ実行開始していないタスク数
- `concurrentLimit`: コンストラクタで指定した同時実行上限

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

該当なし（メモリ上での状態管理のみ）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| InvariantViolation | 実行時エラー | concurrentLimitが0以下 | 正の整数を指定する |
| InvariantViolation | 内部エラー | recentOpenCountが0以下で通知受信 | 内部状態不整合（バグ） |
| InvariantViolation | 内部エラー | runningCount >= concurrentLimitで実行開始 | 内部状態不整合（バグ） |
| Exception | ユーザー例外 | 処理関数内で例外発生 | 呼び出し元でハンドリング |

### リトライ仕様

本機能自体にリトライ機構は組み込まれていない。リトライが必要な場合は呼び出し元で実装する。

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

該当なし

## パフォーマンス要件

- 同時実行数制限のオーバーヘッドは最小限に抑えられている
- 大量のタスク（10,000件以上）でも安定して動作する設計
- blocking dictの操作はO(1)で実行

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

該当なし（ライブラリ内部機能のため）

## 備考

- Semaphoreインスタンスは再利用可能（複数回のwaitForAsync呼び出しが可能）
- 同一リクエスト内でのみ有効（リクエストをまたいだ制御は不可）
- `AwaitAllWaitHandle::fromVec`を使用してactiveGenを更新し、全ての非同期処理を追跡

---

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

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

### 推奨読解順序

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

Semaphoreクラスの内部状態を理解することが重要である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Semaphore.php | `src/async/Semaphore.php` | クラスのプロパティ定義（24-30行目） |

**読解のコツ**: Hackの型パラメータ`<Tin, Tout>`により、入力型と出力型が汎用化されていることに注目。

**主要なプロパティ**:
- **26行目**: `$uniqueIDCounter` - 待機タスクのユニークID生成用カウンタ
- **27行目**: `$blocking` - 待機中タスクのConditionを保持するdict
- **28行目**: `$activeGen` - 全ての非同期処理を追跡するAwaitable
- **29行目**: `$runningCount` - 現在実行中のタスク数
- **30行目**: `$recentOpenCount` - 通知済みだがまだ実行開始していないタスク数

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Condition.php | `src/async/Condition.php` | 待機・通知メカニズムの実装 |

**主要処理フロー**:
- **23-36行目**: `succeed()` - 成功時の通知処理
- **66-73行目**: `waitForNotificationAsync()` - 通知待機処理

#### Step 3: コンストラクタを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Semaphore.php | `src/async/Semaphore.php` | コンストラクタ実装（38-44行目） |

**主要処理フロー**:
- **38-44行目**: 同時実行数の検証とプロパティ初期化
- **42行目**: `invariant($concurrentLimit > 0, ...)` - 入力値検証

#### Step 4: メイン処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | Semaphore.php | `src/async/Semaphore.php` | waitForAsync()メソッド（47-86行目） |

**主要処理フロー**:
- **49-62行目**: 同時実行数チェックと待機処理
- **63-66行目**: 実行スロット確保の検証
- **67-70行目**: 処理関数の実行
- **71-80行目**: finally節でのクリーンアップと次タスク通知
- **82-85行目**: activeGenの更新と結果返却

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

```
Semaphore::waitForAsync($value)
    |
    +-- Semaphore内部async block
    |       |
    |       +-- [条件: 上限到達時]
    |       |       |
    |       |       +-- new Condition()
    |       |       +-- Condition::waitForNotificationAsync($activeGen)
    |       |
    |       +-- $f($value)  [ユーザー定義の処理関数]
    |       |
    |       +-- [finally節]
    |               |
    |               +-- C\first_key($blocking)
    |               +-- Condition::succeed(null)
    |
    +-- AwaitAllWaitHandle::fromVec()
```

### データフロー図

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

Tin $value ──────────> waitForAsync() ──────────> Awaitable<Tout>
                            |
                            v
                    ┌───────────────┐
                    │ 同時実行数    │
                    │ チェック      │
                    └───────┬───────┘
                            |
            ┌───────────────┴───────────────┐
            v                               v
    ┌───────────────┐               ┌───────────────┐
    │ 待機          │               │ 即座に実行    │
    │ (Condition)   │               │               │
    └───────┬───────┘               └───────┬───────┘
            |                               |
            v                               v
    ┌───────────────────────────────────────────────┐
    │            処理関数 $f($value) 実行           │
    └───────────────────────────────────────────────┘
                            |
                            v
                    ┌───────────────┐
                    │ 結果返却      │
                    │ + 次タスク    │
                    │   通知        │
                    └───────────────┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Semaphore.php | `src/async/Semaphore.php` | ソース | Semaphoreクラスの実装 |
| Condition.php | `src/async/Condition.php` | ソース | 待機・通知メカニズムの実装 |
| SemaphoreTest.php | `tests/async/SemaphoreTest.php` | テスト | Semaphoreの単体テスト |
