# 機能設計書 147-ハウスキーピング

## 概要

本ドキュメントは、GitLabのハウスキーピング（リポジトリメンテナンス）機能に関する設計書である。ハウスキーピング機能はリポジトリのガベージコレクション、圧縮、最適化を実行し、リポジトリのパフォーマンスとストレージ効率を維持する。

### 本機能の処理概要

ハウスキーピング機能は、Gitリポジトリの定期的なメンテナンス作業を自動化・管理するための機能である。プッシュ回数に基づいた自動実行と、管理者による手動実行の両方をサポートし、リポジトリの健全性を維持する。

**業務上の目的・背景**：Gitリポジトリは継続的な使用によりオブジェクトが蓄積され、パフォーマンスが低下することがある。定期的なガベージコレクション（GC）やリパックによりリポジトリを最適化し、クローン・フェッチの高速化とストレージ使用量の削減を実現する。

**機能の利用シーン**：
- 定期的なリポジトリ最適化（自動実行）
- パフォーマンス問題発生時の手動GC実行
- 大規模な履歴削除後のリポジトリクリーンアップ
- ストレージ使用量削減のための圧縮処理
- 不要なオブジェクト（到達不能オブジェクト）の削除

**主要な処理内容**：
1. プッシュ回数のカウントと閾値判定
2. ガベージコレクション（GC）の実行
3. 増分リパックの実行
4. 到達不能オブジェクトの削除（prune）
5. リースによる排他制御

**関連システム・外部連携**：
- Gitalyサーバー（実際のGC処理実行）
- Sidekiqワーカー（非同期処理）
- アプリケーション設定（housekeeping_enabled等）

**権限による制御**：
- 手動実行にはプロジェクト管理者権限が必要
- 自動実行は権限チェックなし（システム処理）

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | プロジェクト設定画面 | 補助機能 | リポジトリメンテナンス設定 |

## 機能種別

システム管理 / バックグラウンド処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| prune | Boolean | No | 到達不能オブジェクト削除フラグ | true/false |

### 入力データソース

- HTTPリクエスト（手動実行時）
- プッシュイベント（自動実行時）
- アプリケーション設定

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 成功/失敗 | Boolean | 処理結果 |
| エラーメッセージ | String | 失敗時のエラー詳細 |

### 出力先

- リダイレクト（プロジェクト編集画面）
- 監査ログ（Gitlab::Audit::Auditor）
- Sidekiqジョブ（非同期処理）

## 処理フロー

### 処理シーケンス

```
1. ハウスキーピング実行要求
   └─ 手動: ProjectsController#housekeeping
   └─ 自動: HousekeepingService#execute

2. タスク決定
   └─ prune パラメータあり → :prune
   └─ パラメータなし → :eager
   └─ 自動実行: pushes_since_gc に基づき判定

3. リース取得試行
   └─ ExclusiveLease.try_obtain (24時間タイムアウト)
   └─ 取得失敗時は LeaseTaken 例外

4. ガベージコレクション実行
   └─ git_garbage_collect_worker_klass.perform_async
   └─ 非同期でGitaly経由のGC実行

5. カウンタリセット
   └─ pushes_since_gc >= gc_period の場合リセット
```

### フローチャート

```mermaid
flowchart TD
    A[ハウスキーピング要求] --> B{手動/自動}

    B -->|手動| C[タスク決定]
    B -->|自動| D[pushes_since_gc確認]

    C --> E{pruneパラメータ?}
    E -->|Yes| F[タスク = :prune]
    E -->|No| G[タスク = :eager]

    D --> H{period_match?}
    H -->|Yes| I[タスク自動決定]
    H -->|No| J[スキップ]

    F --> K[リース取得試行]
    G --> K
    I --> K

    K --> L{リース取得成功?}
    L -->|Yes| M[監査ログ記録]
    L -->|No| N[LeaseTaken例外]

    M --> O[GCワーカー起動]
    O --> P{pushes >= gc_period?}
    P -->|Yes| Q[カウンタリセット]
    P -->|No| R[完了]
    Q --> R

    N --> S[エラー応答]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-147-01 | リースタイムアウト | ハウスキーピングのリースは24時間有効 | 常時 |
| BR-147-02 | GC周期 | GCは200プッシュごとに実行 | 自動実行 |
| BR-147-03 | 増分リパック周期 | housekeeping_incremental_repack_period設定に従う | 自動実行 |
| BR-147-04 | 有効化設定 | housekeeping_enabledがfalseの場合は実行しない | 自動実行 |
| BR-147-05 | 手動タスク | pruneパラメータで:prune、なしで:eager | 手動実行 |

### 計算ロジック

**タスク決定（自動実行時）**:
```ruby
if pushes_since_gc % gc_period == 0
  :gc
else
  :incremental_repack
end
```

**周期マッチ判定**:
```ruby
def period_match?
  [gc_period, repack_period].any? { |period| pushes_since_gc % period == 0 }
end
```

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| カウンタ取得 | project_statistics | SELECT | pushes_since_gc取得 |
| カウンタ増加 | project_statistics | UPDATE | プッシュごとにインクリメント |
| カウンタリセット | project_statistics | UPDATE | GC実行後にリセット |
| 監査ログ | audit_events | INSERT | 手動実行時のログ記録 |

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

#### project_statistics

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | pushes_since_gc | project_id = :id | カウンタ取得 |
| UPDATE | pushes_since_gc | pushes_since_gc + 1 | increment! |
| UPDATE | pushes_since_gc | 0 | リセット |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | LeaseTaken | 他のハウスキーピングが実行中 | 60分以内に再実行された旨を通知 |

### リトライ仕様

- リースタイムアウト（24時間）後に自動的に実行可能になる
- 手動実行失敗時はアラート表示

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

- カウンタ操作はAtomicに実行
- 監査ログは処理成功後に記録

## パフォーマンス要件

- ハウスキーピング処理は非同期（Sidekiqワーカー）で実行
- 大規模リポジトリでは処理に時間がかかる可能性あり
- Metricsによる処理時間計測

## セキュリティ考慮事項

- 手動実行時の監査ログ記録（Gitlab::Audit::Auditor）
- リースによる多重実行防止

## 備考

- GC_PERIOD = 200（デフォルトのGC周期）
- LEASE_TIMEOUT = 86400（24時間）
- Wikiリポジトリにも適用可能（::Repositories::HousekeepingService.new(project.wiki)）

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: コントローラアクションを理解する

手動実行のエントリーポイントを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | projects_controller.rb | `app/controllers/projects_controller.rb` | housekeepingアクション（264-280行目付近） |

**主要処理フロー**:
1. **264行目**: def housekeeping
2. **265-269行目**: タスク決定（prune or eager）
3. **271行目**: HousekeepingService.new(@project, task).execute
4. **272-277行目**: 監査ログ記録

**読解のコツ**:
- `do...end`ブロックで監査ログ記録を行っている
- pruneパラメータの有無でタスクが変わる

#### Step 2: サービス実装を理解する

ハウスキーピングサービスの詳細を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | housekeeping_service.rb | `app/services/repositories/housekeeping_service.rb` | ハウスキーピングサービス |

**主要処理フロー**:
1. **11-12行目**: LEASE_TIMEOUT, GC_PERIOD定数
2. **21-24行目**: initialize - リソースとタスクの設定
3. **26-33行目**: execute - リース取得とGC実行
4. **35-37行目**: needed? - 実行必要性判定
5. **39-43行目**: increment! - プッシュカウンタ増加
6. **47-55行目**: execute_gitlab_shell_gc - 非同期GC実行
7. **72-80行目**: task - タスク自動決定

**読解のコツ**:
- `try_obtain_lease`でリース取得を試みる
- `block_given?`でブロックが渡された場合は`yield`を実行（監査ログ用）
- `pushes_since_gc`でプッシュ回数を管理

### プログラム呼び出し階層図

```
ProjectsController#housekeeping
    │
    └─ Repositories::HousekeepingService.new(@project, task)
           │
           ├─ execute
           │      ├─ try_obtain_lease
           │      │      └─ Gitlab::ExclusiveLease.new(lease_key, timeout: LEASE_TIMEOUT)
           │      │
           │      ├─ yield (監査ログ記録)
           │      │      └─ Gitlab::Audit::Auditor.audit
           │      │
           │      └─ execute_gitlab_shell_gc(lease_uuid)
           │             ├─ git_garbage_collect_worker_klass.perform_async
           │             └─ reset_pushes_since_gc (条件付き)
           │
           └─ increment! (プッシュ時)
                  └─ @resource.increment_pushes_since_gc
```

### データフロー図

```
[入力]                    [処理]                         [出力]

手動実行要求          ───▶  ProjectsController          ───▶  リダイレクト
(prune param)              ├─ タスク決定
                           └─ HousekeepingService
                                  ├─ リース取得
                                  ├─ 監査ログ
                                  └─ GCワーカー起動

プッシュイベント      ───▶  HousekeepingService         ───▶  GC実行 or スキップ
                           ├─ increment!
                           ├─ needed?
                           └─ execute
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| projects_controller.rb | `app/controllers/projects_controller.rb` | コントローラ | 手動実行エントリーポイント |
| housekeeping_service.rb | `app/services/repositories/housekeeping_service.rb` | サービス | ハウスキーピングサービス |
| exclusive_lease.rb | `lib/gitlab/exclusive_lease.rb` | ライブラリ | 排他リース管理 |
| auditor.rb | `lib/gitlab/audit/auditor.rb` | ライブラリ | 監査ログ |
| git_garbage_collect_worker.rb | `app/workers/git_garbage_collect_worker.rb` | ワーカー | GC非同期処理 |
| project_statistics.rb | `app/models/project_statistics.rb` | モデル | プッシュカウンタ管理 |
| application_setting.rb | `app/models/application_setting.rb` | モデル | ハウスキーピング設定 |
