# バッチ設計書 46-Users::MigrateRecordsToGhostUserInBatchesWorker

## 概要

本ドキュメントは、GitLabにおけるゴーストユーザーへのレコード移行バッチ（Users::MigrateRecordsToGhostUserInBatchesWorker）の設計仕様を定義したものである。

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

削除されたユーザーに関連するレコード（Issue、MergeRequest、コメント等）を「Ghost User」に移行するバッチ処理である。

**業務上の目的・背景**：GitLabでは、ユーザーが削除された場合でも、そのユーザーが作成したIssue、MergeRequest、コメント等のコンテンツは保持される必要がある。本バッチは、削除されたユーザーに関連付けられていたレコードを特別な「Ghost User」に再割り当てすることで、参照整合性を維持しつつ、ユーザー削除後もコンテンツを保持することを目的としている。これにより、プロジェクト履歴の継続性が確保される。

**バッチの実行タイミング**：2分間隔で実行

**主要な処理内容**：
1. GhostUserMigrationテーブルから移行対象ジョブを取得
2. 各ジョブに対してMigrateRecordsToGhostUserServiceを実行
3. 対象レコードをGhost Userに移行
4. 処理完了またはタイムアウトまで継続

**前後の処理との関連**：ユーザー削除処理（Users::DestroyService）がGhostUserMigrationレコードを作成し、本バッチがそれを処理する。

**影響範囲**：issues、merge_requests、notes等のauthor_id関連カラム、users_ghost_user_migrationsテーブル

## バッチ種別

データ移行 / データクレンジング

## 実行スケジュール

| 項目 | 内容 |
|-----|------|
| 実行頻度 | 2分間隔 |
| 実行時刻 | */2（2分ごと） |
| 実行曜日 | 毎日 |
| 実行日 | - |
| トリガー | cron |

## 実行条件

### 前提条件

| 条件 | 説明 |
|-----|------|
| データベース接続 | 各種テーブルへのアクセスが可能であること |
| 排他ロック取得 | in_lockでリースを取得できること |

### 実行可否判定

ExclusiveLeaseHelpersを使用し、同一バッチの重複実行を防止する。リースが取得できない場合はスキップする。

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | デフォルト値 | 説明 |
|-------------|-----|-----|-------------|------|
| なし | - | - | - | 本バッチはパラメータを受け取らない |

### 入力データソース

| データソース | 形式 | 説明 |
|-------------|------|------|
| users_ghost_user_migrations | DB | 移行対象ジョブ |

## 出力仕様

### 出力データ

| 出力先 | 形式 | 説明 |
|-------|------|------|
| 各種テーブル | DB | author_id等をGhost Userに更新 |
| users_ghost_user_migrations | DB | 処理完了レコードの削除または再スケジュール |

### 出力ファイル仕様

ファイル出力はなし

## 処理フロー

### 処理シーケンス

```
1. バッチ開始
   └─ CronjobQueueからperformメソッドが呼び出される
2. 排他ロック取得
   └─ in_lockでリースを取得（TTL: MAX_RUNTIME）
3. サービス呼び出し
   └─ MigrateRecordsToGhostUserInBatchesServiceを実行
4. 移行ジョブ取得
   └─ GhostUserMigration.consume_orderで最大1000件取得
5. 各ジョブ処理
   └─ MigrateRecordsToGhostUserServiceを実行
6. タイムアウト制御
   └─ ExecutionTrackerで実行時間を監視
7. エラー時再スケジュール
   └─ 30分後に再試行するよう更新
8. バッチ終了
```

### フローチャート

```mermaid
flowchart TD
    A[バッチ開始] --> B{排他ロック取得可能?}
    B -->|いいえ| K[バッチ終了]
    B -->|はい| C[GhostUserMigration取得 LIMIT:1000]
    C --> D{移行ジョブ存在?}
    D -->|なし| K
    D -->|あり| E[MigrateRecordsToGhostUserService実行]
    E --> F{ExecutionTracker超過?}
    F -->|はい| K
    F -->|いいえ| G{処理成功?}
    G -->|はい| H[次のジョブ?]
    G -->|いいえ| I[30分後に再スケジュール]
    I --> H
    H -->|あり| J{ExecutionTracker超過?}
    J -->|はい| K
    J -->|いいえ| E
    H -->|なし| K
```

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

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

| 処理 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 移行ジョブ取得 | users_ghost_user_migrations | SELECT | 処理対象ジョブを取得 |
| レコード移行 | issues, merge_requests, notes等 | UPDATE | author_idをGhost Userに更新 |
| 再スケジュール | users_ghost_user_migrations | UPDATE | consume_afterを30分後に更新 |
| ジョブ完了 | users_ghost_user_migrations | DELETE | 処理完了したジョブを削除 |

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

#### users_ghost_user_migrations

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | user_id, initiator_user_id, hard_delete | consume_order | 消費順序でソート |
| UPDATE | consume_after | 30.minutes.from_now | エラー時再スケジュール |
| DELETE | - | 処理完了時 | ジョブの削除 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ExecutionTimeOutError | 実行時間超過 | 正常終了（次回継続） |
| - | StandardError | その他のエラー | エラートラッキング後、30分後に再スケジュール |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 無制限（30分後に再スケジュール） |
| リトライ間隔 | 30分 |
| リトライ対象エラー | StandardError全般 |

### 障害時対応

個別ジョブのエラーは30分後に再スケジュールされる。バッチ全体の障害時は次回cron実行時に再処理される。sidekiq_options retry: falseにより、Sidekiqレベルのリトライは無効。

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

| 項目 | 内容 |
|-----|------|
| トランザクション範囲 | 個別ジョブ単位 |
| コミットタイミング | 各ジョブ処理完了時 |
| ロールバック条件 | ジョブ処理中のエラー発生時 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定処理件数 | 最大1000ジョブ/実行 |
| 目標処理時間 | ExecutionTracker::MAX_RUNTIME内 |
| メモリ使用量上限 | LIMIT_SIZE: 1000による制御 |

## 排他制御

- idempotent!で宣言されており、冪等性が保証されている
- Gitlab::ExclusiveLeaseHelpersを使用した排他制御
- in_lock(self.class.name.underscore, ttl: MAX_RUNTIME, retries: 0)でリースを取得
- 同一バッチの重複実行を防止

## ログ出力

| ログ種別 | 出力タイミング | 出力内容 |
|---------|--------------|---------|
| 開始ログ | バッチ開始時 | ワーカー名、実行開始時刻 |
| 進捗ログ | 各ジョブ処理時 | 処理対象user_id |
| 終了ログ | バッチ終了時 | 実行完了、処理件数 |
| エラーログ | エラー発生時 | エラーメッセージ、スタックトレース |

## 監視・アラート

| 監視項目 | 閾値 | アラート先 |
|---------|-----|----------|
| 未処理ジョブ数 | 1000件超過 | システム管理者 |
| 処理エラー率 | 10%超過 | システム管理者 |

## 備考

- feature_categoryは「user_profile」に分類される
- data_consistencyは「sticky」で、レプリカDBを使用可能
- sidekiq_options retry: falseにより、Sidekiqのリトライは無効
- hard_deleteフラグにより、完全削除か移行かを制御
- Ghost Userは特別なシステムユーザーで、削除されたユーザーのコンテンツを引き継ぐ
- ExecutionTrackerで実行時間を監視し、タイムアウト時は次回に継続
