# バッチ設計書 96-Ci::ScheduleOldPipelinesRemovalCronWorker

## 概要

本ドキュメントは、CI保持ポリシーに基づいて古いパイプラインの削除をスケジュールするバッチ処理「Ci::ScheduleOldPipelinesRemovalCronWorker」の設計仕様を記載します。

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

**業務上の目的・背景**：GitLabでは、CI/CDパイプラインの実行履歴が蓄積され続けると、データベースとストレージのコストが増大します。プロジェクトごとにCI保持ポリシーを設定することで、一定期間を過ぎた古いパイプラインを自動的に削除できます。このバッチは、保持ポリシーが設定されたプロジェクトをキューに追加し、実際の削除処理を`DestroyOldPipelinesWorker`に委譲します。これにより、ストレージ管理とシステムパフォーマンスの維持を実現します。

**バッチの実行タイミング**：11分ごとに実行されます（cron: `*/11 * * * *`）。頻繁な実行により、新たに保持期限を超えたパイプラインを迅速に処理します。

**主要な処理内容**：
1. `ProjectsCleanupQueue`にCI保持ポリシーが設定されたプロジェクトをエンキュー
2. `DestroyOldPipelinesWorker.perform_with_capacity`を呼び出して並行削除処理を開始
3. `DestroyOldPipelinesWorker`が最大10並列でプロジェクト単位の削除を実行
4. 削除件数がRE_ENQUEUE_THRESHOLD（100件）を超えた場合、プロジェクトを再キューイング

**前後の処理との関連**：このワーカーはスケジューラとして動作し、実際の削除処理は`Ci::DestroyOldPipelinesWorker`が担当します。さらに、各プロジェクトの削除は`Ci::Pipelines::AutoCleanupService`で実行されます。

**影響範囲**：`ci_pipelines`テーブルおよび関連するCI関連テーブル（ジョブ、アーティファクト等）から古いレコードが削除されます。プロジェクトのパイプライン履歴が保持ポリシーに従って整理されます。

## バッチ種別

データクレンジング

## 実行スケジュール

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

## 実行条件

### 前提条件

| 条件 | 説明 |
|-----|------|
| CI機能が有効 | `continuous_integration` feature categoryが有効であること |
| 保持ポリシー設定 | プロジェクトにCI保持ポリシーが設定されていること |

### 実行可否判定

- `idempotent!`により冪等性が保証される
- `deduplicate :until_executed, including_scheduled: true`により重複実行を防止
- 保持ポリシーが設定されたプロジェクトがない場合も正常終了

## 入力仕様

### 入力パラメータ

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

### 入力データソース

| データソース | 形式 | 説明 |
|-------------|------|------|
| projects | DB | プロジェクトテーブル（保持ポリシー設定を持つもの） |
| ci_pipelines | DB | パイプラインテーブル（削除対象） |

## 出力仕様

### 出力データ

| 出力先 | 形式 | 説明 |
|-------|------|------|
| ci_pipelines | DB | 古いパイプラインを削除 |
| 関連CIテーブル | DB | パイプラインに紐づくジョブ、アーティファクト等を削除 |

### 出力ファイル仕様

ファイル出力なし

## 処理フロー

### 処理シーケンス

```
1. ワーカー実行開始（ScheduleOldPipelinesRemovalCronWorker）
   └─ ProjectsCleanupQueue.instance.enqueue_projects! を呼び出し
2. プロジェクトのキューイング
   └─ CI保持ポリシーが設定されたプロジェクトをキューに追加
3. 削除ワーカー起動
   └─ DestroyOldPipelinesWorker.perform_with_capacity を呼び出し
4. 並列削除処理（DestroyOldPipelinesWorker）
   └─ 最大10並列（CONCURRENCY）で実行
   └─ キューから次のプロジェクトIDを取得
   └─ AutoCleanupServiceでパイプライン削除を実行
5. 再キュー判定
   └─ 削除件数が100件超の場合、プロジェクトを再キュー
6. ログ出力
   └─ removed_count, skipped_count, project をメタデータとして出力
```

### フローチャート

```mermaid
flowchart TD
    A[CronWorker開始] --> B[ProjectsCleanupQueue.enqueue_projects!]
    B --> C[DestroyOldPipelinesWorker.perform_with_capacity]
    C --> D[並列ワーカー起動（最大10）]
    D --> E{キューにプロジェクトあり?}
    E -->|あり| F[プロジェクトID取得]
    F --> G[AutoCleanupService実行]
    G --> H[パイプライン削除]
    H --> I{削除件数 > 100?}
    I -->|Yes| J[プロジェクト再キュー]
    I -->|No| K[ログ出力]
    J --> K
    K --> L{キューにまだあり?}
    L -->|あり| E
    L -->|なし| M[処理完了]
    E -->|なし| M
```

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

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

| 処理 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| プロジェクト取得 | projects | SELECT | 保持ポリシー設定プロジェクトを取得 |
| パイプライン削除 | ci_pipelines | DELETE | 古いパイプラインを削除 |
| ジョブ削除 | ci_builds | DELETE | パイプラインに紐づくジョブを削除 |
| アーティファクト削除 | ci_job_artifacts | DELETE | ジョブに紐づくアーティファクトを削除 |

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

#### ci_pipelines

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| DELETE | (全カラム) | 保持期間を超えたパイプライン | AutoCleanupServiceで実行 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | データベース接続エラー | DB接続失敗時 | Sidekiqによる自動リトライ |
| - | キューアクセスエラー | Redis障害時 | 自動リトライ |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | Sidekiqデフォルト（25回） |
| リトライ間隔 | 指数バックオフ |
| リトライ対象エラー | 一時的なエラー全般 |

### 障害時対応

- `idempotent!`により再実行しても整合性が保たれる
- 障害発生時は次回定期実行で自動復旧
- 手動実行する場合は`Ci::ScheduleOldPipelinesRemovalCronWorker.new.perform`を実行

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

| 項目 | 内容 |
|-----|------|
| トランザクション範囲 | パイプライン単位（AutoCleanupService内） |
| コミットタイミング | パイプライン削除完了時 |
| ロールバック条件 | 削除処理中のエラー |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定処理件数 | プロジェクト数に依存 |
| 目標処理時間 | 11分以内（次回実行まで） |
| メモリ使用量上限 | LIMITで制御（250件） |

## 排他制御

- `deduplicate :until_executed, including_scheduled: true`により重複実行を防止
- `LimitedCapacity::Worker`により並列実行数を制御（CONCURRENCY = 10）
- プロジェクト単位でキューから取得することで競合を回避

## ログ出力

| ログ種別 | 出力タイミング | 出力内容 |
|---------|--------------|---------|
| 開始ログ | バッチ開始時 | Sidekiq標準ログ |
| プロジェクトログ | 各プロジェクト処理後 | removed_count, skipped_count, project |
| 終了ログ | バッチ終了時 | Sidekiq標準ログ |
| エラーログ | エラー発生時 | 例外情報 |

## 監視・アラート

| 監視項目 | 閾値 | アラート先 |
|---------|-----|----------|
| 処理時間 | 長時間実行（要調整） | 運用チーム |
| エラー件数 | 連続失敗 | 運用チーム |
| キュー滞留 | 大量蓄積 | 運用チーム |

## 備考

- このワーカーは`continuous_integration` feature categoryに属する
- `data_consistency :sticky`によりプライマリDBを使用
- `urgency :low`により低優先度キューで実行
- 実際の削除は`Ci::DestroyOldPipelinesWorker`と`Ci::Pipelines::AutoCleanupService`が担当
- `LIMIT`: 250件（DestroyOldPipelinesWorkerの1回あたり処理上限）
- `RE_ENQUEUE_THRESHOLD`: 100件（再キューの閾値）
- `CONCURRENCY`: 10（最大並列数）
- Feature flagによりprotected/lockedパイプラインをスキップ可能
