# バッチ設計書 1-runJobs

## 概要

本ドキュメントは、Payloadのジョブキューシステムにおける中核バッチ処理「runJobs」の設計仕様を定義する。このバッチは、キュー内のジョブを取得し実行する責務を担う。

### 本バッチの処理概要

runJobsバッチは、Payloadのジョブキューシステムにおいて、キューに登録されたジョブを取得し、順次または並列で実行する中核的なバッチ処理である。

**業務上の目的・背景**：現代のWebアプリケーションでは、メール送信、画像処理、データ同期など、即座に応答を返す必要がない処理を非同期で実行することが求められる。runJobsバッチは、これらの非同期処理を信頼性高く実行するための基盤を提供し、システムのスケーラビリティと応答性を確保する。

**バッチの実行タイミング**：cronによる定期実行（デフォルトは毎分）、APIエンドポイント経由の手動実行、またはautoRun設定による自動実行。Vercelなどのサーバーレス環境では、Vercel Cronから呼び出すことも可能。

**主要な処理内容**：
1. 実行可能なジョブの検索（completedAt未設定、hasError=false、processing=false、waitUntil条件を満たすもの）
2. 同時実行制御（concurrencyKeyによる排他制御、enableConcurrencyControl有効時）
3. ジョブのprocessingフラグをtrueに更新（他ワーカーとの競合防止）
4. ワークフローまたはタスクハンドラの実行
5. 実行結果に基づくジョブステータスの更新
6. 完了ジョブの削除（deleteJobOnComplete設定時）

**前後の処理との関連**：handleSchedulesバッチによってスケジュールされたジョブを実行する。また、schedulePublishなどのタスクがキューに登録された後、本バッチによって実行される。

**影響範囲**：payload-jobsコレクション内の全ジョブ、および各ジョブが操作対象とするコレクション・グローバルのデータ。

## バッチ種別

ジョブキュー実行処理（非同期タスク実行基盤）

## 実行スケジュール

| 項目 | 内容 |
|-----|------|
| 実行頻度 | 随時（デフォルト：毎分） |
| 実行時刻 | autoRun設定のcronに依存（デフォルト: `* * * * *`） |
| 実行曜日 | 該当なし（cronにより制御） |
| 実行日 | 該当なし（cronにより制御） |
| トリガー | cron/APIエンドポイント/手動 |

## 実行条件

### 前提条件

| 条件 | 説明 |
|-----|------|
| ジョブキュー有効化 | Payload設定でjobs設定が有効であること |
| 実行権限 | jobsConfig.access.run関数がtrueを返すこと（デフォルト：ログインユーザー） |
| 未完了ジョブ存在 | キュー内に実行可能なジョブが存在すること |

### 実行可否判定

以下の条件をすべて満たすジョブが実行対象となる：
- `completedAt`が未設定
- `hasError`がtrueでない
- `processing`がfalse
- `waitUntil`が未設定、または現在時刻より前

同時実行制御有効時（enableConcurrencyControl=true）は、同一concurrencyKeyを持つジョブが実行中でないことも条件に追加される。

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | デフォルト値 | 説明 |
|-------------|-----|-----|-------------|------|
| id | number \| string | No | - | 特定のジョブIDを指定して実行 |
| allQueues | boolean | No | false | trueの場合、全キューのジョブを実行 |
| limit | number | No | 10 | 1回の実行で処理するジョブの最大数 |
| overrideAccess | boolean | No | false | アクセス制御をバイパス |
| processingOrder | Sort | No | createdAt | 処理順序（FIFO: createdAt、LIFO: -createdAt） |
| queue | string | No | 'default' | 対象キュー名 |
| sequential | boolean | No | false | trueの場合、ジョブを逐次実行 |
| silent | RunJobsSilent | No | false | ログ出力の抑制 |
| where | Where | No | - | 追加のフィルター条件 |

### 入力データソース

| データソース | 形式 | 説明 |
|-------------|------|------|
| payload-jobs | DB | ジョブキューコレクション |
| jobsConfig | 設定 | Payload設定のjobs設定 |

## 出力仕様

### 出力データ

| 出力先 | 形式 | 説明 |
|-------|------|------|
| payload-jobs | DB | 更新されたジョブレコード |
| RunJobsResult | オブジェクト | 実行結果（jobStatus、remainingJobsFromQueried、noJobsRemaining） |

### 出力ファイル仕様

ファイル出力なし（データベース更新のみ）

## 処理フロー

### 処理シーケンス

```
1. アクセス権限チェック
   └─ jobsConfig.access.run関数による認可確認
2. 実行可能ジョブの検索条件構築
   └─ completedAt、hasError、processing、waitUntil条件
3. 同時実行制御チェック（enableConcurrencyControl有効時）
   └─ 実行中のconcurrencyKeyを取得し、除外条件に追加
4. ジョブの取得と処理中フラグ更新
   └─ updateJobs()でprocessing=trueに更新しながら取得
5. 同一concurrencyKeyジョブの重複排除
   └─ 同一バッチ内で重複するキーのジョブをリリース
6. ジョブの実行（並列または逐次）
   └─ workflowHandlerまたはtaskHandlerの呼び出し
7. 完了ジョブの削除（deleteJobOnComplete有効時）
   └─ 成功したジョブをDBから削除
8. 実行結果の集計と返却
   └─ jobStatus、remainingJobsFromQueriedの算出
```

### フローチャート

```mermaid
flowchart TD
    A[バッチ開始] --> B{アクセス権限チェック}
    B -->|拒否| C[Forbiddenエラー]
    B -->|許可| D[実行可能ジョブ検索条件構築]
    D --> E{concurrency制御有効?}
    E -->|Yes| F[実行中concurrencyKey取得]
    F --> G[除外条件追加]
    E -->|No| H[ジョブ取得・processing更新]
    G --> H
    H --> I{ジョブ存在?}
    I -->|No| J[noJobsRemaining=true返却]
    I -->|Yes| K{sequential?}
    K -->|Yes| L[逐次実行]
    K -->|No| M[並列実行]
    L --> N{deleteJobOnComplete?}
    M --> N
    N -->|Yes| O[完了ジョブ削除]
    N -->|No| P[結果集計]
    O --> P
    P --> Q[バッチ終了]
```

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

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

| 処理 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| ジョブ取得 | payload-jobs | SELECT/UPDATE | processing=trueに更新しながら取得 |
| 同時実行制御 | payload-jobs | SELECT | concurrencyKey付きの実行中ジョブ検索 |
| ジョブ更新 | payload-jobs | UPDATE | completedAt、totalTried、error等の更新 |
| ジョブ削除 | payload-jobs | DELETE | 完了ジョブの削除（設定有効時） |

### テーブル別操作詳細

#### payload-jobs

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | processing | true | ジョブ取得時に即座に更新 |
| UPDATE | completedAt | ISO日時文字列 | ジョブ成功時 |
| UPDATE | totalTried | 現在値+1 | 実行回数のインクリメント |
| UPDATE | hasError | true | 最大リトライ到達時 |
| UPDATE | error | エラーオブジェクト | エラー発生時 |
| DELETE | - | id IN (成功ジョブID配列) | deleteJobOnComplete有効時 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| Forbidden | 認可エラー | access.run関数がfalseを返却 | 適切な権限を持つユーザーで実行 |
| TaskError | タスクエラー | タスク内でエラー発生 | リトライまたはhasError設定 |
| WorkflowError | ワークフローエラー | ワークフロー内でエラー発生 | リトライまたはhasError設定 |
| JobCancelledError | キャンセル | ジョブがキャンセルされた | hasError=true、cancelled=true設定 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | タスク/ワークフロー設定のretries値に依存 |
| リトライ間隔 | バックオフ設定に依存（指数バックオフ対応） |
| リトライ対象エラー | TaskError、WorkflowError |

### 障害時対応

1. エラーログを確認し、エラーの原因を特定
2. hasError=trueのジョブを手動で修正または削除
3. 必要に応じてジョブを再キューイング

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

| 項目 | 内容 |
|-----|------|
| トランザクション範囲 | ジョブ単位（各ジョブは独立したトランザクション） |
| コミットタイミング | 各ジョブの処理完了時 |
| ロールバック条件 | ジョブ処理中の未処理例外発生時 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定処理件数 | limit設定による（デフォルト10件/実行） |
| 目標処理時間 | ジョブ内容に依存（タイムアウト設定なし） |
| メモリ使用量上限 | 制限なし（depth=0推奨でメモリ効率化） |

## 排他制御

- `processing`フラグによる楽観的ロック：ジョブ取得時にprocessing=trueに更新することで、他ワーカーとの競合を防止
- `concurrencyKey`による排他制御：enableConcurrencyControl有効時、同一キーのジョブは同時実行されない
- 同一バッチ内重複排除：同一concurrencyKeyを持つジョブが同時に取得された場合、1つのみ実行し残りはリリース

## ログ出力

| ログ種別 | 出力タイミング | 出力内容 |
|---------|--------------|---------|
| 開始ログ | ジョブ実行開始時 | `Running ${jobs.length} jobs.`、new/retrying件数 |
| エラーログ | エラー発生時 | エラーメッセージ、ジョブID |
| 削除ログ | 完了ジョブ削除失敗時 | `Failed to delete jobs ${ids} on complete` |

## 監視・アラート

| 監視項目 | 閾値 | アラート先 |
|---------|-----|----------|
| hasErrorジョブ数 | 設定による | 運用チーム |
| 長時間processing状態 | 設定による | 運用チーム |

## 備考

- サーバーレス環境（Vercel等）では、autoRunではなくVercel Cron経由での実行を推奨
- depth設定は0を推奨（パフォーマンス最適化のため）
- runHooks=trueは非推奨（パフォーマンス低下の原因）
- 4.0でenableConcurrencyControlはデフォルトtrueになる予定
