# バッチ設計書 9-ExpireBuildArtifactsWorker

## 概要

本ドキュメントは、期限切れのビルドアーティファクトを削除するバッチ処理「ExpireBuildArtifactsWorker」の設計仕様を記載する。

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

ExpireBuildArtifactsWorkerは、有効期限が切れたCIジョブアーティファクト（ビルド成果物）を検出し、削除するバッチ処理である。ストレージ容量の管理とコスト最適化のため、不要になったアーティファクトを定期的にクリーンアップする。

**業務上の目的・背景**：CI/CDパイプラインでは、各ジョブが成果物（アーティファクト）を生成する。これらのアーティファクトには有効期限が設定されており（プロジェクト設定またはジョブ定義で指定）、期限を過ぎたアーティファクトは不要になる。大規模なGitLabインスタンスでは、アーティファクトが大量のストレージを消費するため、定期的な削除が必要である。本バッチは、有効期限切れのアーティファクトを検出し、バッチ処理で効率的に削除することで、ストレージ容量を適正に管理する。

**バッチの実行タイミング**：7分間隔で実行（cron: `*/7 * * * *`）。高頻度で実行することで、期限切れアーティファクトを迅速に削除し、ストレージ使用量を抑制する。

**主要な処理内容**：
1. Feature Flag（bulk_delete_job_artifacts）が有効な場合は処理をスキップ
2. 排他ロック（ExclusiveLease）を取得し、同時実行を防止
3. 有効期限が切れたアーティファクトを検索
4. バッチサイズ100件ずつ、5分または500回のループ上限まで処理
5. DestroyBatchServiceを使用してアーティファクトを削除
6. 削除件数をログに記録

**前後の処理との関連**：本ワーカーはレガシーな削除方式を使用する。Feature Flag `bulk_delete_job_artifacts`が有効な場合は、代わりに`Ci::ScheduleBulkDeleteJobArtifactCronWorker`が使用される。両方のワーカーは排他的に動作する。

**影響範囲**：全プロジェクトのCI/CDジョブアーティファクトに影響。アーティファクト削除によりストレージが解放され、ダウンロード不可になる。

## バッチ種別

データクレンジング / ストレージ管理

## 実行スケジュール

| 項目 | 内容 |
|-----|------|
| 実行頻度 | 7分間隔 |
| 実行時刻 | 毎時0分、7分、14分、21分、28分、35分、42分、49分、56分 |
| 実行曜日 | 毎日 |
| 実行日 | 毎日 |
| トリガー | cron (`*/7 * * * *`) |

## 実行条件

### 前提条件

| 条件 | 説明 |
|-----|------|
| Feature Flag無効 | `bulk_delete_job_artifacts`フラグが無効であること |
| 排他ロック取得 | ExclusiveLeaseを取得できること |
| 期限切れアーティファクト存在 | 有効期限が切れたアーティファクトが存在すること |

### 実行可否判定

1. Feature Flag `bulk_delete_job_artifacts`が有効な場合は処理をスキップ
2. 排他ロック（ExclusiveLease）を取得できた場合のみ処理を実行（TTL: 6分）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | デフォルト値 | 説明 |
|-------------|-----|-----|-------------|------|
| なし | - | - | - | cronジョブとして引数なしで実行 |

### 入力データソース

| データソース | 形式 | 説明 |
|-------------|------|------|
| ci_job_artifacts | DB | ジョブアーティファクトテーブル |

## 出力仕様

### 出力データ

| 出力先 | 形式 | 説明 |
|-------|------|------|
| ci_job_artifacts | DB | レコード削除 |
| オブジェクトストレージ | ファイル削除 | アーティファクトファイル削除 |

### 出力ファイル仕様

ファイル出力なし（ファイル削除のみ）。

## 処理フロー

### 処理シーケンス

```
1. Feature Flagチェック
   └─ bulk_delete_job_artifactsが有効ならreturn
2. 排他ロック取得
   └─ ExclusiveLeaseHelpers.in_lockでロック取得（TTL: 6分）
3. ループ処理開始
   └─ 5分のタイムアウトと500回のリミットを設定
4. 期限切れアーティファクト取得
   └─ expired_before(@start_at).non_trace.artifact_unlocked.limit(100)
5. バッチ削除実行
   └─ DestroyBatchService.new(artifacts, skip_projects_on_refresh: true).execute
6. 削除件数カウント
   └─ @removed_artifacts_count += destroyed_artifacts_count
7. ログ出力
   └─ destroyed_job_artifacts_countをメタデータに記録
```

### フローチャート

```mermaid
flowchart TD
    A[バッチ開始] --> B{Feature Flag有効?}
    B -->|はい| I[バッチ終了]
    B -->|いいえ| C{排他ロック取得}
    C -->|成功| D[期限切れアーティファクト検索]
    C -->|失敗| I
    D --> E{アーティファクト存在?}
    E -->|なし| H{タイムアウト or ループ上限?}
    E -->|あり| F[DestroyBatchService実行]
    F --> G[削除件数カウント]
    G --> H
    H -->|はい| I
    H -->|いいえ| D
```

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

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

| 処理 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 期限切れアーティファクト取得 | ci_job_artifacts | SELECT | expire_at < now、non_trace、artifact_unlocked |
| アーティファクト削除 | ci_job_artifacts | DELETE | レコード削除 |

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

#### ci_job_artifacts

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | 全カラム | expire_at < @start_at, file_type != trace, locked = 0 | バッチサイズ100件 |
| DELETE | - | 取得したレコードを削除 | DestroyBatchServiceで実行 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ExclusiveLease取得失敗 | 別プロセスがロック保持中 | スキップ |
| - | ファイル削除失敗 | オブジェクトストレージエラー | エラーログ出力、継続 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 1回（ExclusiveLease取得） |
| リトライ間隔 | - |
| リトライ対象エラー | ロック取得失敗 |

### 障害時対応

1. ロック取得失敗の場合：次回実行時に自動復旧
2. ファイル削除失敗の場合：次回実行時にリトライ

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

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

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定処理件数 | バッチサイズ100件 × 最大500回 = 最大50,000件 |
| 目標処理時間 | 5分以内（LOOP_TIMEOUT） |
| メモリ使用量上限 | バッチサイズ100件による制御 |

## 排他制御

- ExclusiveLease（TTL: 6分）による排他制御
- 同時に1プロセスのみ実行可能
- ロックキー: `expired_job_artifacts:destroy:lock`

## ログ出力

| ログ種別 | 出力タイミング | 出力内容 |
|---------|--------------|---------|
| 開始ログ | バッチ開始時 | Sidekiq標準ログ |
| メタデータ | バッチ終了時 | destroyed_job_artifacts_count |
| エラーログ | エラー発生時 | 例外情報 |

## 監視・アラート

| 監視項目 | 閾値 | アラート先 |
|---------|-----|----------|
| 処理時間 | 6分超過 | 運用チーム |
| 削除件数 | 異常増減 | 運用チーム |

## 備考

- `data_consistency :always`が設定されており、プライマリDBを使用
- `feature_category :job_artifacts`でジョブアーティファクト機能として分類
- Feature Flag `bulk_delete_job_artifacts`が有効な場合は動作しない
- BATCH_SIZE = 100, LOOP_LIMIT = 500, LOOP_TIMEOUT = 5.minutes
- LOCK_TIMEOUT = 6.minutes（cron間隔7分より短い）
- non_traceスコープ：トレースファイルは別途管理されるため除外
- artifact_unlockedスコープ：ロックされたアーティファクトは保護される
- skip_projects_on_refresh: trueでリフレッシュ中のプロジェクトをスキップ
