# 画面設計書 1-All Jobs（全ジョブ一覧）

## 概要

本ドキュメントは、Apache Spark Web UIの「All Jobs（全ジョブ一覧）」画面の設計書である。SparkUIのデフォルト画面（/jobs/にリダイレクト）として、全ジョブの進捗状況をタイムライン・テーブル形式で表示し、ジョブのKill操作も提供する。

### 本画面の処理概要

**業務上の目的・背景**：Sparkアプリケーション実行中に、ユーザーがジョブの進捗状況をリアルタイムで監視し、問題が発生した場合に迅速に対処するための画面である。全ジョブをActive/Completed/Failedに分類し、タイムライン表示によりジョブとExecutorの時系列での動きを視覚的に把握できる。パフォーマンスチューニングやデバッグ時に、どのジョブがいつ開始され完了したか、並列度はどうだったかを確認する用途で使用される。

**画面へのアクセス方法**：SparkアプリケーションのWeb UI（デフォルトポート4040）にアクセスすると、ルート（/）から/jobs/にリダイレクトされ、本画面が表示される。ナビゲーションバーの「Jobs」タブからもアクセス可能。

**主要な操作・処理内容**：
1. アプリケーション情報のサマリー表示（ユーザー名、開始時刻、稼働時間、スケジューリングモード）
2. Event Timeline表示によるジョブとExecutorの時系列可視化（折りたたみ可能、ズーム対応）
3. Active Jobs テーブルの表示（ページング・ソート対応）
4. Completed Jobs テーブルの表示（ページング・ソート対応）
5. Failed Jobs テーブルの表示（ページング・ソート対応）
6. Active Jobに対するKill操作（確認ダイアログ付き）

**画面遷移**：
- この画面からの遷移先：Job Detail（ジョブ詳細）画面（ジョブID選択時）
- この画面への遷移元：ルート（/）からのリダイレクト、他の全画面からのナビゲーションバー経由

**権限による表示制御**：Kill操作は`killEnabled`設定がtrueかつセキュリティマネージャの`checkModifyPermissions`で許可されたユーザーのみ実行可能。ACLが有効な場合、管理者権限を持つユーザーのみKillリンクが表示される。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 17 | Spark Web UI | 主機能 | AppStatusStoreからジョブ一覧を取得しActive/Completed/Failedに分類してテーブル・タイムライン表示する主処理 |
| 3 | DAGスケジューラ | API連携 | ジョブのステージ分割情報を参照し、各ジョブのステージ数・完了ステージ数を非同期で取得・表示 |
| 5 | Executorプロセス管理 | 補助機能 | Executorのタイムライン（追加・削除イベント）をジョブタイムラインと合わせて表示 |
| 12 | メトリクスシステム | 補助機能 | ジョブのタスク完了数・失敗数等のメトリクスを収集し進捗バーとして表示 |
| 95 | KVStore | API連携 | AppStatusStore経由でKVStoreに永続化されたジョブデータを非同期取得 |

## 画面種別

一覧

## URL/ルーティング

- パス: `/jobs/`
- クラス: `AllJobsPage` (WebUIPage(""))
- タブ: `JobsTab` (SparkUITab(parent, "jobs"))
- リダイレクト: `/` -> `/jobs/`

## 入出力項目

| 項目名 | 入出力 | 型 | 説明 |
|--------|--------|------|------|
| activeJob.page | 入力（URL パラメータ） | Int | Active Jobsテーブルのページ番号 |
| activeJob.sort | 入力（URL パラメータ） | String | Active Jobsテーブルのソートカラム名 |
| activeJob.desc | 入力（URL パラメータ） | Boolean | Active Jobsテーブルのソート順（降順フラグ） |
| activeJob.pageSize | 入力（URL パラメータ） | Int | Active Jobsテーブルの1ページあたり表示件数 |
| completedJob.page | 入力（URL パラメータ） | Int | Completed Jobsテーブルのページ番号 |
| completedJob.sort | 入力（URL パラメータ） | String | Completed Jobsテーブルのソートカラム名 |
| completedJob.desc | 入力（URL パラメータ） | Boolean | Completed Jobsテーブルのソート順 |
| completedJob.pageSize | 入力（URL パラメータ） | Int | Completed Jobsテーブルの1ページあたり表示件数 |
| failedJob.page | 入力（URL パラメータ） | Int | Failed Jobsテーブルのページ番号 |
| failedJob.sort | 入力（URL パラメータ） | String | Failed Jobsテーブルのソートカラム名 |
| failedJob.desc | 入力（URL パラメータ） | Boolean | Failed Jobsテーブルのソート順 |
| failedJob.pageSize | 入力（URL パラメータ） | Int | Failed Jobsテーブルの1ページあたり表示件数 |

## 表示項目

### サマリーセクション

| 項目名 | データソース | 説明 |
|--------|-------------|------|
| User | parent.getSparkUser | アプリケーションの実行ユーザー名 |
| Started At | appInfo.attempts.head.startTime | アプリケーションの開始日時 |
| Total Uptime | endTime - startTime | アプリケーションの稼働時間 |
| Scheduling Mode | SCHEDULER_MODE設定値 | スケジューリングモード（FIFO/FAIR/Unknown） |
| Active Jobs | activeJobs.size | アクティブなジョブ数（リンク付き） |
| Completed Jobs | completedJobs.size / appSummary.numCompletedJobs | 完了したジョブ数 |
| Failed Jobs | failedJobs.size | 失敗したジョブ数（リンク付き） |

### Event Timeline

| 項目名 | データソース | 説明 |
|--------|-------------|------|
| Jobs タイムライン | makeJobEvent(jobs) | ジョブの開始・終了をバー形式で表示（Succeeded=緑、Failed=赤、Running=青） |
| Executors タイムライン | makeExecutorEvent(executors) | Executorの追加・削除イベントをポイント表示 |

### ジョブテーブル（Active/Completed/Failed共通）

| カラム名 | ソート可否 | データソース | 説明 |
|----------|-----------|-------------|------|
| Job Id (Job Group) | 可 | jobData.jobId, jobData.jobGroup | ジョブIDとジョブグループ |
| Description | 可 | jobData.description / lastStageDescription | ジョブの説明（最後のステージの説明を使用） |
| Submitted | 可 | jobData.submissionTime | ジョブの投入日時 |
| Duration | 可 | completionTime - submissionTime | ジョブの実行時間 |
| Stages: Succeeded/Total | 不可 | numCompletedStages / stageIds.size | 完了ステージ数/総ステージ数 |
| Tasks (for all stages): Succeeded/Total | 不可 | numCompletedIndices / numTasks | 完了タスク数/総タスク数（プログレスバー表示） |

## イベント仕様

### 1-ジョブID選択

Job Idカラムのリンクをクリックすると、Job Detail（ジョブ詳細）画面に遷移する。遷移先URL: `{basePath}/jobs/job/?id={jobId}`

### 2-Kill操作

Active Jobsテーブルにて、killEnabledがtrueの場合に表示される「(kill)」リンクをクリックする。確認ダイアログ「Are you sure you want to kill job {jobId} ?」が表示され、OKを選択するとKillリクエストが送信される。リクエスト先URL: `{basePath}/jobs/job/kill/?id={jobId}`。JobsTabの`handleKillRequest`メソッドにて、セキュリティチェック後に`SparkContext.cancelJob`が呼び出される。100msの待機後にページがリフレッシュされる。

### 3-テーブルソート

各テーブルのカラムヘッダーをクリックすると、そのカラムでソートされる。ソート可能カラム: Job Id, Description, Submitted, Duration。再クリックでソート順が反転する。

### 4-テーブルページング

テーブル下部のページナビゲーションでページ遷移が可能。ページサイズも変更可能。

### 5-Event Timelineの折りたたみ

「Event Timeline」ラベルをクリックすると、タイムラインの表示/非表示が切り替わる。

### 6-Event Timelineのズーム

「Enable zooming」チェックボックスをオンにすると、タイムラインのズーム操作が有効になる。

## データベース更新仕様

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| ページ表示 | KVStore (AppStatusStore) | SELECT | ジョブ一覧・Executor一覧・アプリケーション情報・環境情報の読み取り |
| Kill操作 | なし（RPC経由） | - | SparkContext.cancelJobによりDAGSchedulerにキャンセルリクエスト送信 |

### テーブル別更新項目詳細

本画面はデータの読み取り専用であり、KVStoreへの直接的な書き込みは行わない。Kill操作はRPC経由でDAGSchedulerにキャンセルリクエストを送信し、その結果としてリスナーイベント経由でKVStoreが更新される。

## メッセージ仕様

| 種別 | メッセージ | 表示条件 |
|------|----------|----------|
| 確認 | "Are you sure you want to kill job {jobId} ?" | Kill操作時のJavaScript確認ダイアログ |
| 情報 | "A job is triggered by an action, like count() or saveAsTextFile(). Click on a job to see information about the stages of tasks inside it." | ページヘッダーのヘルプテキスト |
| 情報 | "Only the most recent {MAX_TIMELINE_JOBS} submitted/completed jobs (of {total} total) are shown." | タイムラインに表示するジョブ数が上限を超えた場合 |
| 情報 | "Only the most recent {MAX_TIMELINE_EXECUTORS} added/removed executors (of {total} total) are shown." | タイムラインに表示するExecutor数が上限を超えた場合 |
| エラー | "Error while rendering job table: {exception}" | テーブルレンダリング中にIllegalArgumentException/IndexOutOfBoundsExceptionが発生した場合 |

## 例外処理

| 例外 | 発生条件 | 処理 |
|------|----------|------|
| IllegalArgumentException | 不正なソートカラム名が指定された場合 | エラーメッセージをテーブル領域にalertとして表示 |
| IndexOutOfBoundsException | 不正なページ番号が指定された場合 | エラーメッセージをテーブル領域にalertとして表示 |

## 備考

- タイムライン表示は`spark.ui.timeline.enabled`設定で無効化可能（デフォルト: true）
- タイムラインに表示するジョブの最大数は`spark.ui.timeline.jobs.maximum`で設定可能（デフォルト: 500）
- タイムラインに表示するExecutorの最大数は`spark.ui.timeline.executors.maximum`で設定可能（デフォルト: 250）
- Completed Jobsの表示数がnumCompletedJobsと異なる場合は「{total}, only showing {displayed}」形式で表示される（ガベージコレクションで古いジョブが削除された場合）
- スケジューリングモードがUnknownと表示される場合は、SPARK-33991の対応として列挙型変換エラーを回避している

---

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

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

### 推奨読解順序

#### Step 1: データ構造を理解する

まず、画面で扱うデータモデルを理解する。ジョブ情報はREST API用のv1データクラスとして定義されている。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | api.scala | `core/src/main/scala/org/apache/spark/status/api/v1/api.scala` | JobData, ExecutorSummary, ApplicationInfoなどのデータクラス定義。各フィールドの意味を理解する |
| 1-2 | AppStatusStore.scala | `core/src/main/scala/org/apache/spark/status/AppStatusStore.scala` | jobsList(), executorList(), applicationInfo(), appSummary()等のデータ取得APIを理解する |

**読解のコツ**: Scalaのケースクラスでデータモデルが定義されている。JobExecutionStatusの列挙型（RUNNING, SUCCEEDED, FAILED, UNKNOWN）がジョブの状態分類に使われる。

#### Step 2: エントリーポイントを理解する

処理の起点となるAllJobsPage.renderメソッドを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | AllJobsPage.scala | `core/src/main/scala/org/apache/spark/ui/jobs/AllJobsPage.scala` | renderメソッド（278行目）がHTTPリクエストを受けてHTML Nodeを返す主処理 |

**主要処理フロー**:
1. **279行目**: `store.applicationInfo()` でアプリケーション情報を取得
2. **288行目**: `store.jobsList(null)` で全ジョブ一覧を取得し、ステータス別にListBufferに分類
3. **299-304行目**: ステータス別にjobsTableを呼び出してテーブルHTMLを生成
4. **310行目**: `store.appSummary()` でジョブ数サマリーを取得
5. **318-321行目**: `store.environmentInfo()` からスケジューリングモードを取得
6. **323-374行目**: サマリーHTMLを構築（ユーザー名、開始時刻、稼働時間など）
7. **377-378行目**: `makeTimeline()` でタイムラインを生成
8. **380-418行目**: Active/Completed/Failedの各セクションをHTMLに追加
9. **423-424行目**: `UIUtils.headerSparkPage()` でページ全体をラップ

#### Step 3: タイムライン生成処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | AllJobsPage.scala | `core/src/main/scala/org/apache/spark/ui/jobs/AllJobsPage.scala` | makeTimeline（173行目）、makeJobEvent（71行目）、makeExecutorEvent（126行目）の3メソッドでタイムラインJSONを生成 |

**主要処理フロー**:
- **71-124行目**: makeJobEventで各ジョブをタイムラインイベントJSON文字列に変換。submissionTimeとcompletionTimeで開始・終了を設定
- **126-171行目**: makeExecutorEventで各Executorの追加・削除イベントをJSON文字列に変換
- **173-242行目**: makeTimelineで2つのグループ（executors, jobs）を持つタイムラインHTMLとJavaScriptを生成。drawApplicationTimeline関数を呼び出す

#### Step 4: テーブル生成処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | AllJobsPage.scala | `core/src/main/scala/org/apache/spark/ui/jobs/AllJobsPage.scala` | JobPagedTable（508行目）がページング付きテーブルのHTML生成を担当。JobDataSource（440行目）がデータのソート・スライスを担当 |

**主要処理フロー**:
- **440-506行目**: JobDataSourceがJobDataをJobTableRowDataに変換し、ソート済みデータを保持
- **508-618行目**: JobPagedTableがテーブルHTMLを生成。headers()でカラムヘッダー、row()で各行を定義
- **572-617行目**: row()メソッドでジョブID、Description、Submitted、Duration、ステージ進捗、タスク進捗バーを出力

#### Step 5: Kill処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | JobsTab.scala | `core/src/main/scala/org/apache/spark/ui/jobs/JobsTab.scala` | handleKillRequest（50行目）がKillリクエストを処理。killEnabledかつ権限チェック後にsc.cancelJobを呼び出す |

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

```
AllJobsPage.render(request)
    |
    +-- store.applicationInfo()           ... アプリケーション情報取得
    +-- store.jobsList(null)              ... 全ジョブ一覧取得
    |     +-- KVStore.view(JobData)       ... KVStoreからジョブデータ読み取り
    |
    +-- jobsTable()                       ... テーブルHTML生成
    |     +-- new JobPagedTable()
    |           +-- new JobDataSource()
    |                 +-- jobRow()        ... JobData -> JobTableRowData変換
    |                       +-- lastStageNameAndDescription()
    |                       +-- UIUtils.makeDescription()
    |
    +-- store.appSummary()                ... ジョブ数サマリー取得
    +-- store.environmentInfo()           ... スケジューリングモード取得
    +-- makeTimeline()                    ... タイムラインHTML生成
    |     +-- makeJobEvent()             ... ジョブイベントJSON生成
    |     +-- makeExecutorEvent()        ... ExecutorイベントJSON生成
    |     +-- store.executorList(false)  ... Executor一覧取得
    |
    +-- UIUtils.headerSparkPage()         ... ページ全体ラップ

JobsTab.handleKillRequest(request)       ... Kill操作処理
    +-- store.job(id)                    ... ジョブ状態確認
    +-- sc.cancelJob(id, reason)         ... ジョブキャンセル実行
```

### データフロー図

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

HttpServletRequest ---> AllJobsPage.render()
                            |
KVStore(AppStatusStore) --> jobsList(null)          --> Active/Completed/Failed分類
                        --> applicationInfo()        --> サマリー情報
                        --> appSummary()             --> ジョブ数集計
                        --> environmentInfo()        --> スケジューリングモード
                        --> executorList(false)      --> Executorタイムライン
                            |
                            v
                        HTML(Seq[Node])              --> ブラウザ表示
                            |
                        JavaScript                   --> drawApplicationTimeline()
                                                         タイムライン描画
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| AllJobsPage.scala | `core/src/main/scala/org/apache/spark/ui/jobs/AllJobsPage.scala` | ソース | 画面のメインページクラス。render、タイムライン生成、テーブル生成 |
| JobsTab.scala | `core/src/main/scala/org/apache/spark/ui/jobs/JobsTab.scala` | ソース | Jobsタブ定義。Kill操作ハンドラ、FAIRスケジューラ判定 |
| AppStatusStore.scala | `core/src/main/scala/org/apache/spark/status/AppStatusStore.scala` | ソース | データアクセス層。KVStoreのラッパー |
| api.scala | `core/src/main/scala/org/apache/spark/status/api/v1/api.scala` | ソース | REST API用データモデル定義 |
| UIUtils.scala | `core/src/main/scala/org/apache/spark/ui/UIUtils.scala` | ソース | HTML生成ユーティリティ |
| WebUIPage.scala | `core/src/main/scala/org/apache/spark/ui/WebUIPage.scala` | ソース | ページ基底クラス |
| PagedTable.scala | `core/src/main/scala/org/apache/spark/ui/PagedTable.scala` | ソース | ページング付きテーブルの基底クラス |
| StagePage.scala | `core/src/main/scala/org/apache/spark/ui/jobs/StagePage.scala` | ソース | ApiHelper（lastStageNameAndDescription）の定義 |
| timeline-view.js | `core/src/main/resources/org/apache/spark/ui/static/timeline-view.js` | JavaScript | タイムライン描画ライブラリ |
| spark-dag-viz.js | `core/src/main/resources/org/apache/spark/ui/static/spark-dag-viz.js` | JavaScript | DAG可視化ライブラリ |
