# バッチ設計書 73-MergeRequests::ProcessScheduledMergeWorker

## 概要

本ドキュメントは、スケジュールされたマージ処理を実行するバッチ `MergeRequests::ProcessScheduledMergeWorker` の設計仕様を記載する。

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

このバッチは、指定時刻にマージが予約されているマージリクエストを検出し、自動マージ処理をトリガーするワーカーである。

**業務上の目的・背景**：GitLabでは、マージリクエストを特定の時刻にマージする「スケジュールマージ」機能を提供している。この機能により、ユーザーはマージのタイミングを制御でき、例えば業務時間外やデプロイ可能な時間帯にマージを予約できる。このバッチは予約されたマージを適切なタイミングで実行するための重要なインフラストラクチャである。

**バッチの実行タイミング**：毎分（`*/1 * * * *`）にCronジョブとして実行される。

**主要な処理内容**：
1. 排他ロックを取得（5分TTL、最大3回リトライ）
2. マージ予定時刻が現在時刻以前のスケジュールをKeyset Paginationで取得
3. 500件ずつバッチ処理
4. 各マージリクエストに対して `AutoMergeProcessWorker` をエンキュー
5. バッチ間で7秒の遅延を設定して負荷を分散

**前後の処理との関連**：`MergeRequests::MergeSchedule` モデルにマージ予約情報が保存され、このワーカーが予約を検出して `AutoMergeProcessWorker` に処理を委譲する。

**影響範囲**：`merge_request_merge_schedules` テーブル、`merge_requests` テーブル

## バッチ種別

スケジュール実行 / イベント駆動処理

## 実行スケジュール

| 項目 | 内容 |
|-----|------|
| 実行頻度 | 毎分 |
| 実行時刻 | 毎分0秒 |
| 実行曜日 | 全曜日 |
| 実行日 | 毎日 |
| トリガー | cron（`*/1 * * * *`） |

## 実行条件

### 前提条件

| 条件 | 説明 |
|-----|------|
| 排他ロック取得 | 同時実行を防ぐための排他ロック |
| データベース接続 | 読み書き可能な接続 |
| Sidekiq | ジョブのエンキューが可能であること |

### 実行可否判定

- 排他ロックが取得できた場合のみ実行
- ロック取得失敗時は処理をスキップ

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | デフォルト値 | 説明 |
|-------------|-----|-----|-------------|------|
| なし | - | - | - | このワーカーはパラメータを受け取らない |

### 入力データソース

| データソース | 形式 | 説明 |
|-------------|------|------|
| merge_request_merge_schedules | DB | マージスケジュール情報 |
| merge_requests | DB | 自動マージが有効なMR |

## 出力仕様

### 出力データ

| 出力先 | 形式 | 説明 |
|-------|------|------|
| Sidekiq Queue | Job | AutoMergeProcessWorker ジョブ |

### 出力ファイル仕様

ファイル出力なし

## 処理フロー

### 処理シーケンス

```
1. 排他ロック取得
   └─ キー: "merge_requests/process_scheduled_merge_worker"
   └─ TTL: 5分、リトライ: 3回
2. マージスケジュール取得
   └─ Keyset Paginationでmerge_after <= 現在時刻のレコードを取得
   └─ merge_after, merge_request_id でソート
3. バッチ処理（500件ずつ）
   └─ 自動マージ有効なMRをフィルタ
   └─ AutoMergeProcessWorkerをバルクエンキュー
   └─ 遅延: 最初のバッチは1秒後、以降は7秒ずつ増加
4. ロック解放
   └─ 処理完了後に自動解放
```

### フローチャート

```mermaid
flowchart TD
    A[バッチ開始] --> B{排他ロック取得}
    B -->|失敗| C[処理終了]
    B -->|成功| D[スケジュール取得]
    D --> E{レコードあり?}
    E -->|No| F[ロック解放]
    E -->|Yes| G[バッチ取得 500件]
    G --> H[auto_merge有効MRフィルタ]
    H --> I[AutoMergeProcessWorkerエンキュー]
    I --> J[次のバッチ]
    J --> E
    F --> C
```

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

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

| 処理 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| スケジュール取得 | merge_request_merge_schedules | SELECT | マージ予定のスケジュール取得 |
| MR取得 | merge_requests | SELECT | 自動マージ有効なMR取得 |

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

#### merge_request_merge_schedules

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | merge_after, merge_request_id | merge_after <= NOW() | Keyset Pagination |

#### merge_requests

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | id, project_id, merge_user_id | auto_merge_enabled = true | 自動マージ有効フィルタ |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ロック取得失敗 | 他プロセスがロック保持中 | 処理をスキップ、次回実行を待つ |
| - | データベースエラー | DB接続失敗時 | Sidekiqによる自動リトライ |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| ロック取得リトライ回数 | 3回 |
| ロックTTL | 5分 |
| Sidekiqリトライ | デフォルト設定 |

### 障害時対応

- ロック取得失敗時は次回の毎分実行で再試行
- マージ時刻を過ぎたスケジュールは次回実行時に処理される

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

| 項目 | 内容 |
|-----|------|
| トランザクション範囲 | なし（読み取りとエンキューのみ） |
| コミットタイミング | 該当なし |
| ロールバック条件 | 該当なし |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定処理件数 | 可変（バッチサイズ500件） |
| 目標処理時間 | 5分以内（ロックTTL内） |
| メモリ使用量上限 | バッチサイズで制御 |

## 排他制御

- `Gitlab::ExclusiveLeaseHelpers` を使用した排他ロック
- ロックキー: `merge_requests/process_scheduled_merge_worker`
- TTL: 5分
- リトライ: 3回

## ログ出力

| ログ種別 | 出力タイミング | 出力内容 |
|---------|--------------|---------|
| 開始ログ | ジョブ開始時 | ジョブID、クラス名 |
| 終了ログ | ジョブ完了時 | 処理結果 |
| エラーログ | エラー発生時 | 例外情報 |

## 監視・アラート

| 監視項目 | 閾値 | アラート先 |
|---------|-----|----------|
| ジョブ失敗率 | 継続的な失敗 | Sidekiq監視システム |
| 処理時間 | 5分超過 | 管理者通知 |

## 備考

- このワーカーは `idempotent!` として宣言されていない（時間依存のクエリのため）
- feature_category は `code_review_workflow`
- data_consistency は `always` に設定
- worker_resource_boundary は `cpu` に設定（CPU集約型処理）
- Keyset Paginationを使用してパフォーマンスを最適化
- バッチ間の遅延（DELAY = 7秒）で負荷を分散
