# 機能設計書：48-ジョブ管理

## 1. 機能概要

### 1.1 機能の目的
ジョブ管理機能は、CI/CDパイプライン内の個々のジョブ（ビルド、テスト、デプロイ等）を管理する機能である。ジョブの実行、再実行、キャンセル、ログ確認、成果物管理などの操作を提供し、GitLab Runnerとの連携によりジョブを実行する。

### 1.2 関連画面
| 画面ID | 画面名 | パス |
|--------|--------|------|
| SCR-JOBS | ジョブ一覧 | `/:namespace/:project/-/jobs` |
| SCR-JOB | ジョブ詳細 | `/:namespace/:project/-/jobs/:id` |
| SCR-JOB-TRACE | ジョブログ | `/:namespace/:project/-/jobs/:id/trace` |

### 1.3 関連API
| APIエンドポイント | メソッド | 概要 |
|-------------------|----------|------|
| `/projects/:id/jobs` | GET | ジョブ一覧取得 |
| `/projects/:id/jobs/:job_id` | GET | ジョブ詳細取得 |
| `/projects/:id/jobs/:job_id/play` | POST | 手動ジョブ実行 |
| `/projects/:id/jobs/:job_id/retry` | POST | ジョブ再実行 |
| `/projects/:id/jobs/:job_id/cancel` | POST | ジョブキャンセル |
| `/projects/:id/jobs/:job_id/erase` | POST | ジョブ消去 |
| `/projects/:id/jobs/:job_id/trace` | GET | ジョブログ取得 |
| `/projects/:id/jobs/:job_id/artifacts` | GET | 成果物ダウンロード |

## 2. データモデル

### 2.1 主要エンティティ

#### Ci::Build（ジョブ）
```
p_ci_builds テーブル（パーティションテーブル）
├── id: bigint (PK)
├── partition_id: integer (PK)
├── project_id: bigint (FK)
├── commit_id: bigint (FK, pipeline)
├── runner_id: bigint (FK)
├── user_id: bigint (FK)
├── erased_by: bigint (FK)
├── name: varchar(255)
├── ref: varchar
├── tag: boolean
├── status: varchar
├── when: varchar
├── stage: varchar
├── stage_idx: integer
├── allow_failure: boolean
├── timeout: integer
├── timeout_source: smallint
├── coverage: decimal
├── coverage_regex: varchar
├── description: text
├── options: text (serialized)
├── yaml_variables: text (serialized)
├── token_encrypted: bytea
├── artifacts_expire_at: timestamp
├── erased_at: timestamp
├── started_at: timestamp
├── finished_at: timestamp
├── queued_at: timestamp
├── created_at: timestamp
├── updated_at: timestamp
├── scheduling_type: smallint
├── protected: boolean
├── debug_trace_enabled: boolean
└── execution_config_id: bigint (FK)

定数:
- TOKEN_PREFIX = 'glcbt-'
- RUNNERS_STATUS_CACHE_EXPIRATION = 1分
- MAX_PIPELINES_TO_SEARCH = 100
- DEGRADATION_THRESHOLD_VARIABLE_NAME = 'DEGRADATION_THRESHOLD'
```

#### Ci::Processable（抽象基底クラス）
```
Ci::Processable < CommitStatus
├── Ci::Build（ビルドジョブ）
└── Ci::Bridge（トリガージョブ/ダウンストリームパイプライン）

共通属性:
- resource_group_id: リソースグループ
- scheduling_type: stage/dag
- needs: 依存関係
- when: manual/delayed/on_success等
```

#### timeout_source enum
```
- unknown_timeout_source: 1（不明）
- project_timeout_source: 2（プロジェクト設定）
- runner_timeout_source: 3（Runner設定）
- job_timeout_source: 4（ジョブ設定）
```

#### scheduling_type enum
```
- stage: 0（ステージベース）
- dag: 1（DAGベース、needsあり）
```

### 2.2 ER図
```
┌─────────────────────┐      ┌──────────────────┐
│    Ci::Pipeline     │      │    Ci::Runner    │
├─────────────────────┤      ├──────────────────┤
│ id                  │      │ id               │
│ ...                 │      │ ...              │
└─────────────────────┘      └──────────────────┘
         │                            │
         │1                           │1
         ▼ *                          ▼ *
┌─────────────────────────────────────────────────┐
│                   Ci::Build                      │
├─────────────────────────────────────────────────┤
│ id, partition_id                                 │
│ commit_id (pipeline), runner_id                 │
│ name, status, stage, when                        │
│ coverage, timeout, token_encrypted              │
│ options, yaml_variables                          │
└─────────────────────────────────────────────────┘
         │                    │                    │
         │1                   │1                   │1
         ▼ *                  ▼ *                  ▼ *
┌──────────────────┐  ┌──────────────────┐  ┌──────────────────┐
│  Ci::JobArtifact │  │ Ci::BuildTraceChunk│  │  Ci::BuildNeed  │
├──────────────────┤  ├──────────────────┤  ├──────────────────┤
│ id               │  │ id               │  │ id               │
│ job_id           │  │ build_id         │  │ build_id         │
│ file_type        │  │ chunk_index      │  │ name             │
│ file             │  │ data             │  │ artifacts        │
└──────────────────┘  └──────────────────┘  └──────────────────┘
```

## 3. 処理フロー

### 3.1 ジョブ再実行フロー
```
[ユーザー]
     │
     │ retry
     ▼
[Ci::RetryJobService]
     │
     ├── 1. retryable?チェック
     │   └── job.retryable?
     │
     ├── 2. 入力パラメータ処理
     │   └── Ci::Inputs::ProcessorService
     │
     ├── 3. ジョブクローン
     │   └── clone!
     │       ├── check_access!（retry_job権限）
     │       ├── Ci::CloneJobService.execute
     │       ├── 環境リンク
     │       ├── パイプライン開始
     │       └── Ci::CopyCrossDatabaseAssociationsService
     │
     ├── 4. パイプラインに追加
     │   └── Ci::Pipelines::AddJobService
     │
     └── 5. スキップジョブリセット
         └── ResetSkippedJobsService
```

### 3.2 手動ジョブ実行フロー
```
[ユーザー]
     │
     │ play
     ▼
[JobsController#play]
     │
     ├── 1. 権限チェック (play_job)
     │
     ├── 2. playable?チェック
     │
     └── 3. ジョブ実行
         └── @build.play(current_user, job_variables)
             └── Ci::PlayBuildService
```

### 3.3 ジョブキャンセルフロー
```
[ユーザー]
     │
     │ cancel
     ▼
[Ci::BuildCancelService]
     │
     ├── 1. 権限チェック (cancel_build)
     │
     ├── 2. cancelable?チェック
     │
     ├── 3. キャンセル実行
     │   ├── force: false
     │   │   └── build.cancel
     │   └── force: true（maintainer）
     │       └── build.force_cancel
     │
     └── 4. 結果返却
```

### 3.4 ジョブ消去フロー
```
[ユーザー]
     │
     │ erase
     ▼
[Ci::BuildEraseService]
     │
     ├── 1. erasable?チェック
     │
     ├── 2. 成果物削除
     │   └── Ci::JobArtifacts::DestroyBatchService
     │
     ├── 3. トレース削除
     │   └── build.trace.erase!
     │
     └── 4. erased情報更新
         └── erased_by, erased_at, artifacts_expire_at
```

## 4. ジョブ状態

### 4.1 ステータス（CommitStatusから継承）
```
AVAILABLE_STATUSES:
- created: 作成済み
- waiting_for_resource: リソース待ち
- preparing: 準備中
- pending: 保留中（Runner待ち）
- running: 実行中
- success: 成功
- failed: 失敗
- canceled: キャンセル済み
- canceling: キャンセル中
- skipped: スキップ
- manual: 手動待ち
- scheduled: スケジュール済み
```

### 4.2 when（実行条件）
```
- on_success: 前ジョブ成功時（デフォルト）
- on_failure: 前ジョブ失敗時
- always: 常に実行
- manual: 手動実行
- delayed: 遅延実行
- never: 実行しない
```

### 4.3 リソースグループによる制御
```ruby
# Processableでの状態遷移
state_machine :status do
  event :enqueue do
    transition [:created, :skipped, :manual, :scheduled] => :waiting_for_resource,
               if: :with_resource_group?
  end

  event :enqueue_waiting_for_resource do
    transition waiting_for_resource: :preparing, if: :any_unmet_prerequisites?
    transition waiting_for_resource: :pending
  end
end
```

## 5. ビジネスルール

### 5.1 ジョブ操作の権限
| 操作 | 必要権限 | 説明 |
|------|----------|------|
| 詳細表示 | read_build | プロジェクトメンバー |
| ログ表示 | read_build_trace | プロジェクトメンバー |
| 再実行 | retry_job | Developer以上、retryable? |
| 手動実行 | play_job | Developer以上、playable? |
| キャンセル | cancel_build | Developer以上、cancelable? |
| 強制キャンセル | maintainer_access | Maintainer以上、force_cancelable? |
| 消去 | erase_build | 作成者またはMaintainer以上、erasable? |
| ターミナル | create_build_terminal | Developer以上 |

### 5.2 再実行可能条件
```ruby
def retryable?
  success? || failed? || canceled? || (archived_failure? && retried?)
end
```

### 5.3 手動実行可能条件
```ruby
def playable?
  (manual? || scheduled?) && (created? || skipped? || scheduled?)
end
```

### 5.4 消去可能条件
```ruby
def erasable?
  complete? && (artifacts? || has_job_artifacts? || has_trace?)
end
```

### 5.5 キャンセル可能条件
```ruby
CANCELABLE_STATUSES = [:created, :waiting_for_resource, :preparing,
                       :pending, :running, :waiting_for_callback, :scheduled]

def cancelable?
  CANCELABLE_STATUSES.include?(status) && !internal_pipeline?
end
```

### 5.6 クローン属性
```ruby
def clone_accessors
  %i[pipeline project ref tag name allow_failure stage_idx when
    environment coverage_regex description tag_list protected
    needs_attributes job_variables_attributes resource_group
    scheduling_type timeout timeout_source debug_trace_enabled
    ci_stage partition_id execution_config_id inputs_attributes].freeze
end
```

## 6. Runner連携

### 6.1 Runner Features
```ruby
RUNNER_FEATURES = {
  upload_multiple_artifacts: ->(build) { build.publishes_artifacts_reports? },
  refspecs: ->(build) { build.merge_request_ref? || build.workload? },
  artifacts_exclude: ->(build) { build.supports_artifacts_exclude? },
  multi_build_steps: ->(build) { build.multi_build_steps? },
  return_exit_code: ->(build) { build.exit_codes_defined? },
  fallback_cache_keys: ->(build) { build.fallback_cache_keys_defined? }
}
```

### 6.2 ジョブトークン
```ruby
TOKEN_PREFIX = 'glcbt-'

add_authentication_token_field :token,
  encrypted: :required,
  format_with_prefix: :prefix_and_partition_for_token,
  encrypted_token_finder: 'Ci::Jobs::PartitionedTokenFinder'
```

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

### 7.1 読み解く順序
1. **モデル層**: Ci::Processable -> Ci::Build
2. **サービス層**: RetryJobService, BuildCancelService, BuildEraseService
3. **コントローラー層**: JobsController

### 7.2 プログラム呼び出し階層図
```
Ci::RetryJobService
├── check_access!
├── Ci::CloneJobService
│   └── 属性コピー（clone_accessors）
├── Ci::CopyCrossDatabaseAssociationsService
├── Ci::Pipelines::AddJobService
├── MergeRequests::AddTodoWhenBuildFailsService
├── ResetSkippedJobsService
└── Ci::PipelineCreation::StartPipelineService

Ci::BuildCancelService
├── cancel_build権限チェック
├── cancelable?チェック
└── build.cancel / build.force_cancel

Ci::BuildEraseService
├── erasable?チェック
├── Ci::JobArtifacts::DestroyBatchService
├── trace.erase!
└── update(erased_by:, erased_at:)
```

### 7.3 データフロー図
```
[GitLab Runner]
       │
       │ ジョブ要求
       ▼
[Ci::RegisterJobService]
       │
       ├── 実行可能ジョブ検索
       │   └── Ci::PendingBuild (queuing_entry)
       │
       └── ジョブ情報返却
           ├── options (serialized)
           ├── yaml_variables (serialized)
           └── token_encrypted
       │
       ▼
[Runner実行]
       │
       │ 状態更新・ログ送信
       ▼
[Ci::UpdateBuildStateService]
       │
       ├── status更新
       ├── trace_chunks追加
       └── job_artifacts保存
```

### 7.4 関連ファイル一覧
| ファイルパス | 責務 |
|--------------|------|
| `app/models/ci/processable.rb` | 処理可能ジョブの抽象基底クラス |
| `app/models/ci/build.rb` | ビルドジョブモデル |
| `app/models/ci/bridge.rb` | ブリッジジョブ（トリガー）モデル |
| `app/controllers/projects/jobs_controller.rb` | ジョブコントローラー |
| `app/services/ci/retry_job_service.rb` | 再実行サービス |
| `app/services/ci/build_cancel_service.rb` | キャンセルサービス |
| `app/services/ci/build_erase_service.rb` | 消去サービス |
| `app/services/ci/clone_job_service.rb` | ジョブクローンサービス |
| `app/services/ci/play_build_service.rb` | 手動実行サービス |
| `app/models/ci/build_trace_chunk.rb` | ログチャンクモデル |
| `app/models/ci/job_artifact.rb` | ジョブ成果物モデル |
| `app/models/ci/build_need.rb` | 依存関係（needs）モデル |

## 8. 拡張ポイント

### 8.1 EE拡張
- **セキュリティスキャンジョブ**: SASTなどのセキュリティレポート
- **ライセンスコンプライアンス**: ライセンススキャン
- **リソースグループ**: 環境デプロイの排他制御

### 8.2 新規ジョブタイプ追加
1. `Ci::Processable`を継承したクラス作成
2. 必要なバリデーション・スコープ追加
3. `clone_accessors`に新属性追加
4. サービス層で適切な処理追加

### 8.3 Runner Feature追加
1. `RUNNER_FEATURES`に条件追加
2. Runner側でFeatureサポート実装
3. `features`レスポンスに含める
