# バッチ設計書 71-ScheduleMergeRequestCleanupRefsWorker

## 概要

本ドキュメントは、マージリクエストのクリーンアップ参照をスケジュールするバッチ処理 `ScheduleMergeRequestCleanupRefsWorker` の設計仕様を記載する。

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

このバッチは、マージリクエストの Git 参照（refs）のクリーンアップ処理をスケジュールし、実行するワーカーである。

**業務上の目的・背景**：マージリクエストがマージまたはクローズされた後、関連する Git 参照（refs）はリポジトリに残存する。これらの不要な参照を定期的にクリーンアップすることで、リポジトリのサイズを最適化し、Git 操作のパフォーマンスを向上させる。また、停滞したクリーンアップタスクを再試行することで、処理の完全性を担保する。

**バッチの実行タイミング**：毎分（`* * * * *`）Cronジョブとして実行される。ただし、データベースが読み取り専用モードの場合は処理をスキップする。

**主要な処理内容**：
1. データベースが読み取り専用モードかどうかを確認
2. 停滞した（stuck）クリーンアップスケジュールのリトライ処理（`stuck_retry!`）
3. `MergeRequestCleanupRefsWorker` をキャパシティに応じて実行

**前後の処理との関連**：このワーカーは親ワーカーとして機能し、実際のクリーンアップ処理は `MergeRequestCleanupRefsWorker` が担当する。`MergeRequestCleanupRefsWorker` は `LimitedCapacity::Worker` を使用して並列実行数を制御（最大4ジョブ）している。

**影響範囲**：`merge_request_cleanup_schedules` テーブル、Git リポジトリの refs

## バッチ種別

データクレンジング / Git リポジトリメンテナンス

## 実行スケジュール

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

## 実行条件

### 前提条件

| 条件 | 説明 |
|-----|------|
| データベース接続 | 書き込み可能なデータベース接続が必要 |
| Sidekiq | Sidekiqワーカーが稼働していること |

### 実行可否判定

- `Gitlab::Database.read_only?` が `false` の場合のみ実行
- 読み取り専用モードの場合は即座に処理を終了する

## 入力仕様

### 入力パラメータ

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

### 入力データソース

| データソース | 形式 | 説明 |
|-------------|------|------|
| merge_request_cleanup_schedules | DB | クリーンアップスケジュール情報 |

## 出力仕様

### 出力データ

| 出力先 | 形式 | 説明 |
|-------|------|------|
| merge_request_cleanup_schedules | DB | ステータス更新（running → unstarted） |
| Sidekiq Queue | Job | MergeRequestCleanupRefsWorker ジョブ |

### 出力ファイル仕様

ファイル出力なし

## 処理フロー

### 処理シーケンス

```
1. 読み取り専用チェック
   └─ Gitlab::Database.read_only? で確認
2. 停滞タスクのリトライ
   └─ MergeRequest::CleanupSchedule.stuck_retry! を実行
   └─ 6時間以上 running 状態のタスクを unstarted に戻す（最大5件）
3. クリーンアップワーカーの実行
   └─ MergeRequestCleanupRefsWorker.perform_with_capacity を実行
   └─ キャパシティに応じてジョブをエンキュー
```

### フローチャート

```mermaid
flowchart TD
    A[バッチ開始] --> B{読み取り専用?}
    B -->|Yes| C[処理終了]
    B -->|No| D[停滞タスクのリトライ]
    D --> E[CleanupRefsWorker実行]
    E --> F[バッチ終了]
    C --> F
```

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

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

| 処理 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| stuck_retry! | merge_request_cleanup_schedules | UPDATE | 停滞タスクのステータスをリトライ状態に変更 |
| perform_with_capacity | merge_request_cleanup_schedules | SELECT/UPDATE | スケジュール済みタスクの取得と実行 |

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

#### merge_request_cleanup_schedules

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | id, status, updated_at | status = 1 (running) AND updated_at <= 6時間前 | 停滞タスク検索 |
| UPDATE | status, failed_count | status: 1→0, failed_count: +1 | リトライ処理 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | データベース接続エラー | DB接続失敗時 | Sidekiqによる自動リトライ |
| - | レコードロックエラー | 同時更新競合時 | トランザクション再試行 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | Sidekiqデフォルト |
| リトライ間隔 | Sidekiqデフォルト |
| リトライ対象エラー | 標準例外 |

### 障害時対応

- バッチ失敗時は次回のCron実行で自動的に再処理される
- 停滞タスクは `stuck_retry!` で自動的に再試行される

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

| 項目 | 内容 |
|-----|------|
| トランザクション範囲 | `stuck_retry!` はレコード単位 |
| コミットタイミング | 各レコード更新時 |
| ロールバック条件 | 個別レコード更新失敗時 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定処理件数 | 停滞タスクのリトライは最大5件/回 |
| 目標処理時間 | 1分以内（次回実行までに完了） |
| メモリ使用量上限 | 制限なし（軽量処理） |

## 排他制御

- `MergeRequestCleanupRefsWorker` は `LimitedCapacity::Worker` を使用し、最大4つの同時実行ジョブに制限
- `stuck_retry!` は各レコードに対して個別にリトライ処理を実行

## ログ出力

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

## 監視・アラート

| 監視項目 | 閾値 | アラート先 |
|---------|-----|----------|
| ジョブ失敗率 | 継続的な失敗 | Sidekiq監視システム |
| 停滞タスク数 | 多数の停滞タスク | 管理者通知 |

## 備考

- このワーカーは `idempotent!` として宣言されており、同じ処理を複数回実行しても安全
- feature_category は `code_review_workflow`
- data_consistency は `always` に設定されている
