# 機能設計書 13-ワーカー

## 概要

本ドキュメントは、Laravel Frameworkのキューワーカー（Worker）機能の設計を詳細に記述したものである。キューからジョブを取得し実行する長時間稼働プロセスを管理し、リトライ、タイムアウト、メンテナンスモード対応などの高度な機能を提供する。

### 本機能の処理概要

ワーカーは、キューに投入されたジョブを継続的に監視・取得・実行する長時間稼働プロセスである。エラーハンドリング、リトライ機構、メモリ管理など、本番運用に必要な堅牢性を備えている。

**業務上の目的・背景**：非同期処理基盤において、キューに投入されたジョブを確実に処理するワーカープロセスは不可欠である。ワーカーは、ジョブの取得から実行、エラー処理、リトライまでの一連のライフサイクルを管理し、システムの信頼性と可用性を保証する。また、メンテナンスモードやグレースフルシャットダウンへの対応により、運用時の柔軟性を提供する。

**機能の利用シーン**：
- Artisan queue:work コマンドによるワーカー起動
- Supervisor等によるプロセス管理下での稼働
- Horizonによる高度なキュー監視・管理
- 開発環境でのジョブ実行テスト

**主要な処理内容**：
1. デーモンループによる継続的なジョブ監視（daemon メソッド）
2. キューからのジョブ取得（getNextJob メソッド）
3. ジョブの実行とイベント発行（process メソッド）
4. タイムアウト検知とシグナルハンドリング（registerTimeoutHandler メソッド）
5. 最大試行回数超過時の失敗処理（markJobAsFailedIfWillExceedMaxAttempts メソッド）
6. メモリ制限と停止条件のチェック（stopIfNecessary メソッド）

**関連システム・外部連携**：
- キュー管理（QueueManager）：接続の取得
- キャッシュ：リスタートシグナルと一時停止状態の管理
- イベントディスパッチャー：ジョブライフサイクルイベントの発行
- 例外ハンドラー：エラーのレポート

**権限による制御**：ワーカー自体は権限制御を持たないが、実行するジョブ内で個別の権限チェックを実装可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 本機能は画面に直接関連しない |

## 機能種別

バッチ処理 / デーモン / ジョブ実行

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| connectionName | string | Yes | キュー接続名 | 有効な接続名 |
| queue | string | Yes | キュー名（カンマ区切りで複数指定可） | - |
| options | WorkerOptions | Yes | ワーカー設定オプション | - |

### WorkerOptions の詳細

| プロパティ | 型 | デフォルト | 説明 |
|-----------|-----|----------|------|
| memory | int | 128 | メモリ制限（MB） |
| timeout | int | 60 | ジョブタイムアウト（秒） |
| sleep | int | 3 | ジョブがない場合のスリープ（秒） |
| rest | int | 0 | ジョブ実行後の休憩（秒） |
| maxTries | int | 1 | 最大試行回数 |
| maxJobs | int | 0 | 処理ジョブ数上限（0は無制限） |
| maxTime | int | 0 | 最大稼働時間（秒、0は無制限） |
| force | bool | false | メンテナンスモード中も実行 |
| stopWhenEmpty | bool | false | キューが空になったら停止 |
| backoff | int | 0 | リトライ前の待機時間（秒） |

### 入力データソース

- コマンドライン：Artisan queue:work からの引数
- キュー：各ドライバからのジョブ取得
- キャッシュ：リスタートシグナルと一時停止状態

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| exitCode | int | プロセス終了コード（0=成功、1=エラー、12=メモリ超過） |
| events | Event[] | ジョブライフサイクルイベント |

### 出力先

- 標準出力：ログ出力（ロガー経由）
- イベントシステム：JobProcessing、JobProcessed、JobFailed等

## 処理フロー

### 処理シーケンス

```
1. デーモン開始
   └─ daemon($connectionName, $queue, $options) 呼び出し
2. シグナルハンドラー登録
   └─ pcntlサポート時にSIGTERM、SIGQUIT等を登録
3. ワーカー開始イベント発行
   └─ WorkerStartingイベントをディスパッチ
4. メインループ開始
   └─ while(true) による無限ループ
5. 実行可否チェック
   └─ メンテナンスモード、一時停止状態をチェック
6. ジョブ取得
   └─ getNextJob でキューからジョブを取得
7. タイムアウトハンドラー設定
   └─ pcntl_alarm でタイムアウト検知
8. ジョブ実行
   └─ process でジョブを実行
9. 停止条件チェック
   └─ メモリ、ジョブ数、時間、リスタートシグナル
10. 次のイテレーションへ
    └─ スリープ後にループ継続
```

### フローチャート

```mermaid
flowchart TD
    A[daemon開始] --> B[シグナルハンドラー登録]
    B --> C[WorkerStartingイベント]
    C --> D{daemonShouldRun?}
    D -->|No| E[pauseWorker]
    E --> F{stopIfNecessary?}
    D -->|Yes| G[getNextJob]
    G --> H[タイムアウト設定]
    H --> I{ジョブあり?}
    I -->|Yes| J[runJob]
    I -->|No| K[sleep]
    J --> L[restスリープ]
    L --> F
    K --> F
    F -->|停止必要| M[stop]
    F -->|継続| D
    M --> N[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-13-01 | メンテナンスモード | メンテナンス中はジョブを処理しない（forceオプションで上書き可） | メンテナンスモード時 |
| BR-13-02 | キュー優先順位 | カンマ区切りで指定されたキューは左から順に処理 | 複数キュー指定時 |
| BR-13-03 | 最大試行回数 | maxTriesを超えたジョブは失敗としてマーク | リトライ時 |
| BR-13-04 | retryUntil | retryUntilが設定されている場合は時間ベースのリトライ制御 | retryUntil設定時 |
| BR-13-05 | グレースフルシャットダウン | SIGTERM/SIGQUIT受信時は現在のジョブ完了後に停止 | シグナル受信時 |
| BR-13-06 | メモリ制限 | メモリ使用量が制限を超えたら終了 | メモリチェック時 |

### 計算ロジック

```php
// メモリ超過チェック
memoryExceeded = (memory_get_usage(true) / 1024 / 1024) >= $memoryLimit

// バックオフ計算
backoff = $backoff[$job->attempts() - 1] ?? last($backoff)

// 稼働時間チェック
elapsedTime = hrtime(true) / 1e9 - $startTime
shouldStop = $maxTime && $elapsedTime >= $maxTime
```

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

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

Worker自体は直接データベースを操作しない。ジョブの取得・更新は各Queueドライバが担当。

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| - | - | - | Worker自体はDB操作なし |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| EXIT_SUCCESS (0) | 正常終了 | グレースフルシャットダウン | 正常終了、再起動可能 |
| EXIT_ERROR (1) | エラー終了 | タイムアウト、例外発生 | ログ確認、再起動 |
| EXIT_MEMORY_LIMIT (12) | メモリ超過 | メモリ制限超過 | メモリ設定見直し、再起動 |

### リトライ仕様

- ジョブのbackoffプロパティまたはWorkerOptionsのbackoffで待機時間を指定
- カンマ区切りで試行回数ごとの待機時間を指定可能（例："3,10,30"）
- 最後の値を超えた試行は最後の値を継続使用

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

Worker自体はトランザクションを使用しない。各ジョブ内でのトランザクション管理はジョブの責務。

## パフォーマンス要件

- ジョブなし時のスリープでCPU負荷を軽減
- メモリリーク検出のためのメモリ監視
- pcntl拡張によるタイムアウト検知でハング防止
- 接続ロスト検出による自動再起動

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

- ジョブペイロードは信頼できるソースからのみ受け入れ
- 例外情報は適切にマスク・ログ出力
- ワーカープロセスは適切な権限で実行

## 備考

- pcntl拡張が利用可能な場合のみタイムアウト検知が有効
- Octane環境では特別な考慮が必要
- Supervisor等のプロセスマネージャーとの併用を推奨

---

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

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

### 推奨読解順序

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

まず、ワーカーが保持するデータ構造と状態を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Worker.php | `src/Illuminate/Queue/Worker.php` | プロパティ定義（$manager, $events, $cache, $exceptions）を確認 |
| 1-2 | Worker.php | `src/Illuminate/Queue/Worker.php` | 定数定義（EXIT_SUCCESS, EXIT_ERROR, EXIT_MEMORY_LIMIT）を確認 |
| 1-3 | Worker.php | `src/Illuminate/Queue/Worker.php` | 静的プロパティ（$restartable, $pausable）を確認 |

**読解のコツ**: Workerクラスは複数の依存を持つ。`$manager`はキュー管理、`$events`はイベント発行、`$cache`はリスタートシグナル管理、`$exceptions`はエラーレポートに使用される。

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

デーモンループのエントリーポイントを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Worker.php | `src/Illuminate/Queue/Worker.php` | daemonメソッド（154-225行目）でメインループ |
| 2-2 | Worker.php | `src/Illuminate/Queue/Worker.php` | listenForSignalsメソッド（790-799行目）でシグナル登録 |

**主要処理フロー**:
1. **154-159行目**: 非同期シグナルサポートの確認とシグナルハンドラー登録
2. **160-164行目**: 最後のリスタートタイムスタンプ取得、開始時刻記録
3. **166-224行目**: メインwhileループ - ジョブ取得、実行、停止条件チェック

#### Step 3: ジョブ処理フローを理解する

ジョブ取得から実行までのフローを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Worker.php | `src/Illuminate/Queue/Worker.php` | getNextJobメソッド（371-406行目）でジョブ取得 |
| 3-2 | Worker.php | `src/Illuminate/Queue/Worker.php` | runJobメソッド（432-441行目）でジョブ実行開始 |
| 3-3 | Worker.php | `src/Illuminate/Queue/Worker.php` | processメソッド（466-497行目）でジョブ処理 |

**主要処理フロー**:
- **371-406行目**: `getNextJob` - 複数キューから順にジョブを取得、一時停止チェック
- **432-441行目**: `runJob` - processを呼び出し、例外をキャッチしてログ
- **466-497行目**: `process` - 試行回数チェック、fire()実行、イベント発行

#### Step 4: エラーハンドリングを理解する

タイムアウトと失敗処理を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | Worker.php | `src/Illuminate/Queue/Worker.php` | registerTimeoutHandlerメソッド（234-264行目） |
| 4-2 | Worker.php | `src/Illuminate/Queue/Worker.php` | handleJobExceptionメソッド（510-545行目） |
| 4-3 | Worker.php | `src/Illuminate/Queue/Worker.php` | markJobAsFailedIfWillExceedMaxAttemptsメソッド（587-598行目） |

**主要処理フロー**:
- **234-264行目**: `registerTimeoutHandler` - SIGALRMで タイムアウト検知、失敗マーク
- **510-545行目**: `handleJobException` - 例外発生時の失敗チェックとジョブリリース
- **648-651行目**: `failJob` - ジョブの失敗処理を実行

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

```
Worker::daemon($connectionName, $queue, $options)
    │
    ├─ Worker::listenForSignals()
    │      └─ pcntl_signal(SIGTERM/SIGQUIT/SIGINT...)
    │
    ├─ Worker::getTimestampOfLastQueueRestart()
    │      └─ Cache::get('illuminate:queue:restart')
    │
    ├─ Worker::raiseWorkerStartingEvent()
    │      └─ Events::dispatch(WorkerStarting)
    │
    └─ while(true)
           │
           ├─ Worker::daemonShouldRun($options)
           │      ├─ isDownForMaintenance()
           │      └─ Events::until(Looping)
           │
           ├─ Worker::getNextJob($connection, $queue)
           │      ├─ Worker::queuePaused()
           │      └─ Queue::pop($queue)
           │
           ├─ Worker::registerTimeoutHandler($job, $options)
           │      └─ pcntl_alarm($timeout)
           │
           ├─ Worker::runJob($job, $connectionName, $options)
           │      └─ Worker::process($connectionName, $job, $options)
           │             ├─ Worker::raiseBeforeJobEvent()
           │             ├─ Worker::markJobAsFailedIfAlreadyExceedsMaxAttempts()
           │             ├─ Job::fire()
           │             ├─ Worker::raiseAfterJobEvent()
           │             └─ Worker::handleJobException()
           │
           └─ Worker::stopIfNecessary($options, $lastRestart...)
                  ├─ Worker::memoryExceeded()
                  └─ Worker::queueShouldRestart()
```

### データフロー図

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

キュー接続        ───▶  QueueManager::connection() ───▶  Queueインスタンス
    │                        │
キュー名          ───▶  Queue::pop()               ───▶  Jobインスタンス
    │                        │
WorkerOptions     ───▶  process()                  ───▶  ジョブ実行結果
    │                        │
                         raiseEvents()             ───▶  イベント発行
                             │                          ├─ JobProcessing
                             │                          ├─ JobProcessed
                             │                          └─ JobFailed
                             │
                         stopIfNecessary()         ───▶  終了コード
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Worker.php | `src/Illuminate/Queue/Worker.php` | ソース | ワーカーコア実装 |
| WorkerOptions.php | `src/Illuminate/Queue/WorkerOptions.php` | ソース | ワーカーオプション |
| QueueManager.php | `src/Illuminate/Queue/QueueManager.php` | ソース | キュー管理 |
| MaxAttemptsExceededException.php | `src/Illuminate/Queue/MaxAttemptsExceededException.php` | ソース | 最大試行超過例外 |
| TimeoutExceededException.php | `src/Illuminate/Queue/TimeoutExceededException.php` | ソース | タイムアウト例外 |
| DetectsLostConnections.php | `src/Illuminate/Database/DetectsLostConnections.php` | トレイト | 接続ロスト検出 |
| Events/JobProcessing.php | `src/Illuminate/Queue/Events/JobProcessing.php` | ソース | 処理開始イベント |
| Events/JobProcessed.php | `src/Illuminate/Queue/Events/JobProcessed.php` | ソース | 処理完了イベント |
| Events/JobFailed.php | `src/Illuminate/Queue/Events/JobFailed.php` | ソース | 失敗イベント |
| Events/JobTimedOut.php | `src/Illuminate/Queue/Events/JobTimedOut.php` | ソース | タイムアウトイベント |
| Events/WorkerStarting.php | `src/Illuminate/Queue/Events/WorkerStarting.php` | ソース | ワーカー開始イベント |
| Events/WorkerStopping.php | `src/Illuminate/Queue/Events/WorkerStopping.php` | ソース | ワーカー停止イベント |
