# 機能設計書 43-jest-worker

## 概要

本ドキュメントは、jest-workerパッケージの機能設計について記載する。jest-workerは、並列処理のためのワーカープール管理機能を提供し、子プロセスまたはワーカースレッドを使用してタスクを分散実行する。

### 本機能の処理概要

jest-workerは、複数のワーカープロセス/スレッドを管理し、タスクを効率的に分散処理するためのフレームワークである。テスト実行の並列化、コード変換の並列処理など、CPU集約的な作業の高速化を実現する。

**業務上の目的・背景**：大規模なテストスイートや多数のファイル変換を単一プロセスで処理すると、マルチコアCPUのリソースを十分に活用できない。jest-workerは、複数のワーカーにタスクを分散することで、利用可能なCPUコアを最大限活用し、処理時間を大幅に短縮する。これにより、開発者の待ち時間とCI/CDパイプラインの実行時間が削減される。

**機能の利用シーン**：Jest内部ではテストファイルの並列実行、Babelによるコード変換の並列処理などに使用される。また、外部パッケージとしても提供され、任意の並列処理タスクに活用できる。

**主要な処理内容**：
1. Worker: ワーカーファームのメインクラス。ワーカーモジュールのパスを受け取り、メソッド呼び出しを分散
2. Farm: タスクキューとワーカーへのディスパッチを管理
3. WorkerPool: ワーカープロセス/スレッドのプールを管理
4. FifoQueue/PriorityQueue: タスクキューの実装（先入れ先出し/優先度付き）
5. ChildProcessWorker/NodeThreadsWorker: 子プロセス/ワーカースレッドの実装

**関連システム・外部連携**：Node.jsのchild_processモジュール（fork）およびworker_threadsモジュールを使用。標準入出力ストリームのマージにmerge-streamを使用。

**権限による制御**：特になし。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 9 | Jest Platformページ | 補助機能 | ワーカープール管理の利用方法 |

## 機能種別

並列処理 / プロセス管理 / タスクキュー

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| workerPath | string \| URL | Yes | ワーカーモジュールの絶対パス | 絶対パスである必要がある |
| options.numWorkers | number | No | ワーカー数（デフォルト: CPUコア数-1） | 1以上 |
| options.enableWorkerThreads | boolean | No | ワーカースレッド使用（デフォルト: false） | - |
| options.exposedMethods | Array<string> | No | エクスポートするメソッド名 | - |
| options.maxRetries | number | No | 最大リトライ回数（デフォルト: 3） | 0以上 |
| options.forkOptions | ForkOptions | No | fork時のオプション | - |
| options.resourceLimits | ResourceLimits | No | ワーカースレッドのリソース制限 | - |
| options.computeWorkerKey | function | No | ワーカー固定キー計算関数 | - |
| options.taskQueue | TaskQueue | No | カスタムタスクキュー | - |
| options.workerSchedulingPolicy | string | No | スケジューリングポリシー（round-robin/in-order） | - |
| options.idleMemoryLimit | number | No | アイドル時メモリ上限 | 0以上 |

### 入力データソース

- ワーカーモジュール（JavaScriptファイル）
- メソッド呼び出しの引数

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| result | Promise<unknown> | ワーカーメソッドの戻り値 |
| PoolExitResult | object | 終了時の情報（forceExited: boolean） |

### 出力先

- 呼び出し元へのPromise
- stdout/stderrストリーム

## 処理フロー

### 処理シーケンス

```
1. Workerインスタンス作成
   └─ workerPathとoptionsを受け取り、WorkerPoolとFarmを初期化
2. ワーカープール起動
   └─ numWorkers分のワーカープロセス/スレッドを生成
3. メソッド呼び出し
   └─ 公開メソッドが呼び出されると、Farm.doWork()にディスパッチ
4. タスクキューイング
   └─ FifoQueue/PriorityQueueにタスクを追加
5. ワーカー選択
   └─ computeWorkerKeyがあればキャッシュされたワーカーを使用、なければスケジューリングポリシーに従う
6. タスク実行
   └─ 選択されたワーカーにメッセージ送信
7. 結果返却
   └─ ワーカーからの応答をPromiseで返却
8. 終了処理
   └─ end()でワーカーにCHILD_MESSAGE_ENDを送信、タイムアウト後は強制終了
```

### フローチャート

```mermaid
flowchart TD
    A[Worker作成] --> B[WorkerPool初期化]
    B --> C[Farm初期化]
    C --> D[メソッド呼び出し]
    D --> E[Farm.doWork]
    E --> F{computeWorkerKey?}
    F -->|Yes| G[キャッシュからワーカー取得]
    F -->|No| H[スケジューリングポリシー適用]
    G --> I[タスクキュー追加]
    H --> I
    I --> J[ワーカーにメッセージ送信]
    J --> K[結果待機]
    K --> L{成功?}
    L -->|Yes| M[Promiseをresolve]
    L -->|No| N{リトライ可能?}
    N -->|Yes| J
    N -->|No| O[Promiseをreject]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-43-01 | デフォルトワーカー数 | availableParallelism() - 1（最低1） | numWorkers未指定時 |
| BR-43-02 | スケジューリングポリシー | round-robin（デフォルト）またはin-order | タスク割り当て時 |
| BR-43-03 | Stickyワーカー | computeWorkerKeyが同じ値を返す場合、同じワーカーを使用 | computeWorkerKey設定時 |
| BR-43-04 | 強制終了タイムアウト | CHILD_MESSAGE_END送信後500ms経過で強制終了 | end()呼び出し時 |
| BR-43-05 | アイドルメモリ制限 | idleMemoryLimit=0の場合、毎回ワーカーを再起動 | タスク完了時 |

### 計算ロジック

ワーカー選択（round-robin）:
```
offset = this._offset++
workerIndex = offset % numWorkers
```

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

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

該当なし（データベース操作は行わない）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | Error | workerPathが絶対パスでない | 絶対パスを指定 |
| - | TypeError | 予約済みメソッド名を使用 | 別のメソッド名を使用 |
| - | Error | 終了後にメソッド呼び出し | end()呼び出し前に完了 |
| PARENT_MESSAGE_CLIENT_ERROR | ワーカーエラー | ワーカー内でエラー発生 | エラーをPromiseでreject |
| PARENT_MESSAGE_SETUP_ERROR | セットアップエラー | ワーカー初期化失敗 | 設定を見直し |

### リトライ仕様

- maxRetries回数までリトライ（デフォルト: 3回）
- ワーカープロセス/スレッドがクラッシュした場合に再起動してリトライ

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

該当なし

## パフォーマンス要件

- ワーカー起動: 数百ミリ秒
- タスクディスパッチ: ミリ秒単位
- 強制終了タイムアウト: 500ms

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

- ワーカーモジュールはrequire()で動的にロードされる
- child_processのforkまたはworker_threadsを使用し、プロセス間で分離

## 備考

- enableWorkerThreads=trueでワーカースレッド使用（Node.js 12+推奨）
- ワーカーからのカスタムメッセージはUNSTABLE_onCustomMessageで受信可能

---

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

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

### 推奨読解順序

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

まず、ワーカー関連の型定義を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | types.ts | `packages/jest-worker/src/types.ts` | WorkerFarmOptions、WorkerPoolOptions、WorkerInterface、メッセージ型を把握 |

**読解のコツ**: CHILD_MESSAGE_*とPARENT_MESSAGE_*の定数でプロセス間通信のプロトコルを理解する。

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

Workerクラスの全体構造を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | index.ts | `packages/jest-worker/src/index.ts` | Workerクラスの初期化とメソッドバインディング |

**主要処理フロー**:
1. **36-56行目**: getExposedMethods - 公開メソッドの自動検出
2. **89-134行目**: コンストラクタ - WorkerPoolとFarmの初期化
3. **136-152行目**: _bindExposedWorkerMethods - メソッドのバインディング
4. **155-164行目**: _callFunctionWithArgs - メソッド呼び出しの委譲
5. **178-185行目**: end - 終了処理

#### Step 3: Farmタスク管理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Farm.ts | `packages/jest-worker/src/Farm.ts` | タスクキューとディスパッチロジック |

**主要処理フロー**:
- **33-42行目**: コンストラクタ - スケジューリングポリシーとタスクキュー設定
- **44-110行目**: doWork - メインのタスク実行メソッド
- **112-153行目**: _process - ワーカーへのタスク送信
- **155-168行目**: _push - タスクキューへの追加とワーカー選択
- **170-177行目**: _getNextWorkerOffset - round-robin/in-order選択

#### Step 4: WorkerPoolを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | WorkerPool.ts | `packages/jest-worker/src/WorkerPool.ts` | ワーカープールの具体実装 |
| 4-2 | BaseWorkerPool.ts | `packages/jest-worker/src/base/BaseWorkerPool.ts` | ワーカープールの基底クラス |

**主要処理フロー**:
- **WorkerPool.ts 31-40行目**: createWorker - enableWorkerThreadsに応じてワーカー生成
- **BaseWorkerPool.ts 34-72行目**: コンストラクタ - ワーカー配列とストリームマージ
- **BaseWorkerPool.ts 112-133行目**: start - ワーカー起動とセットアップ
- **BaseWorkerPool.ts 135-168行目**: end - 終了処理と強制終了

#### Step 5: キュー実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | FifoQueue.ts | `packages/jest-worker/src/FifoQueue.ts` | 先入れ先出しキュー |
| 5-2 | PriorityQueue.ts | `packages/jest-worker/src/PriorityQueue.ts` | 優先度付きキュー |

**読解のコツ**: TaskQueueインターフェースのenqueue/dequeueメソッドを確認。

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

```
Worker
    │
    ├─ constructor(workerPath, options)
    │      ├─ WorkerPool(workerPath, poolOptions)
    │      │      └─ createWorker() × numWorkers
    │      │             ├─ ChildProcessWorker または
    │      │             └─ NodeThreadsWorker
    │      │
    │      └─ Farm(numWorkers, callback, farmOptions)
    │             └─ FifoQueue または PriorityQueue
    │
    ├─ [exposedMethod](...args)
    │      └─ _callFunctionWithArgs(method, ...args)
    │             └─ Farm.doWork(method, ...args)
    │                    ├─ computeWorkerKey? → キャッシュ参照
    │                    ├─ taskQueue.enqueue(task)
    │                    └─ _process(workerId)
    │                           └─ callback(workerId, request, ...)
    │                                  └─ WorkerPool.send()
    │
    └─ end()
           └─ WorkerPool.end()
                  └─ worker.send(CHILD_MESSAGE_END)
                         └─ forceExit() (500ms後)
```

### データフロー図

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

メソッド呼び出し ────────▶ Farm.doWork() ─────────────────▶ Promise
                              │
                              ├─ computeWorkerKey() → キー計算
                              │
                              └─ taskQueue.enqueue()
                                     │
                                     ▼
                              _process(workerId)
                                     │
                                     ▼
                              WorkerPool.send()
                                     │
                                     ▼
                              ワーカープロセス/スレッド
                                     │
                                     ▼
                              PARENT_MESSAGE_OK/ERROR
                                     │
                                     ▼
                              Promise resolve/reject
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| index.ts | `packages/jest-worker/src/index.ts` | ソース | エントリーポイント、Workerクラス |
| types.ts | `packages/jest-worker/src/types.ts` | ソース | 型定義、定数 |
| Farm.ts | `packages/jest-worker/src/Farm.ts` | ソース | タスクディスパッチ |
| WorkerPool.ts | `packages/jest-worker/src/WorkerPool.ts` | ソース | ワーカープール実装 |
| BaseWorkerPool.ts | `packages/jest-worker/src/base/BaseWorkerPool.ts` | ソース | ワーカープール基底クラス |
| FifoQueue.ts | `packages/jest-worker/src/FifoQueue.ts` | ソース | FIFOキュー |
| PriorityQueue.ts | `packages/jest-worker/src/PriorityQueue.ts` | ソース | 優先度付きキュー |
| ChildProcessWorker.ts | `packages/jest-worker/src/workers/ChildProcessWorker.ts` | ソース | 子プロセスワーカー |
| NodeThreadsWorker.ts | `packages/jest-worker/src/workers/NodeThreadsWorker.ts` | ソース | ワーカースレッド |
| processChild.ts | `packages/jest-worker/src/workers/processChild.ts` | ソース | 子プロセス側ハンドラ |
| threadChild.ts | `packages/jest-worker/src/workers/threadChild.ts` | ソース | スレッド側ハンドラ |
| messageParent.ts | `packages/jest-worker/src/workers/messageParent.ts` | ソース | 親への通信 |
