# 機能設計書 16-定期タスク管理

## 概要

本ドキュメントは、RuoYiシステムにおける定期タスク管理機能の詳細設計を記述する。定期タスク管理機能は、Quartzスケジューラを使用した定期実行タスクの作成、編集、削除、実行制御を提供する。

### 本機能の処理概要

定期タスク管理機能は、システム内で定期的に実行されるバッチ処理やメンテナンスタスクを管理するための包括的な機能を提供する。Quartzフレームワークを基盤とし、Cron式によるスケジュール設定、タスクの即時実行、ステータス管理などを行う。

**業務上の目的・背景**：エンタープライズシステムでは、データ集計、ログ整理、通知送信など、定期的に実行が必要な処理が多数存在する。これらをGUIで管理可能にすることで、開発者やシステム管理者がコード変更なしにタスクスケジュールを調整でき、運用効率が向上する。また、タスクの実行状況を可視化することで、問題の早期発見が可能になる。

**機能の利用シーン**：
- 新規定期タスクの登録時
- 既存タスクのスケジュール変更時
- タスクの一時停止・再開時
- タスクの即時実行（テストや緊急実行）時
- Cron式の検証・確認時

**主要な処理内容**：
1. タスク一覧の表示・検索
2. 新規タスクの登録（Cron式、呼び出し先、並行実行設定など）
3. 既存タスクの編集
4. タスクの削除
5. タスクのステータス変更（正常/一時停止）
6. タスクの即時実行
7. Cron式の有効性検証
8. 次回実行予定時刻の取得
9. タスク情報のExcelエクスポート

**関連システム・外部連携**：Quartzスケジューラと連携してタスク実行を管理する。

**権限による制御**：
- `monitor:job:view` - 定期タスク画面の閲覧
- `monitor:job:list` - タスク一覧の取得
- `monitor:job:add` - タスクの新規登録
- `monitor:job:edit` - タスクの編集
- `monitor:job:remove` - タスクの削除
- `monitor:job:changeStatus` - ステータス変更・即時実行
- `monitor:job:detail` - タスク詳細の閲覧
- `monitor:job:export` - Excelエクスポート

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 52 | 定時任務管理一覧 | 主画面 | タスク一覧の検索、表示、ステータス変更、即時実行処理 |
| 53 | 定時任務新規登録 | 登録画面 | 新規タスク情報入力と登録保存処理 |
| 54 | 定時任務編集 | 編集画面 | タスク情報の更新保存処理 |
| 55 | 定時任務詳細 | 詳細画面 | タスク情報の詳細表示処理 |
| 57 | Cron式生成器 | 補助画面 | Cron式の生成とバリデーション処理 |

## 機能種別

CRUD操作 / スケジューラ制御 / Excelエクスポート

## 入力仕様

### 入力パラメータ

#### タスク登録・編集

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| jobId | Long | No（登録時） | タスクID | 編集時必須 |
| jobName | String | Yes | タスク名 | 最大64文字、空白不可 |
| jobGroup | String | No | タスクグループ | デフォルト値あり |
| invokeTarget | String | Yes | 呼び出し先文字列 | 最大1000文字、ホワイトリストチェック |
| cronExpression | String | Yes | Cron式 | 最大255文字、有効なCron式 |
| misfirePolicy | String | No | ミスファイアポリシー | 0:デフォルト、1:即時実行、2:1回実行、3:実行しない |
| concurrent | String | No | 並行実行許可 | 0:許可、1:禁止 |
| status | String | No | ステータス | 0:正常、1:一時停止 |

### 入力データソース

- 画面入力
- DBテーブル sys_job

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| jobId | Long | タスクID |
| jobName | String | タスク名 |
| jobGroup | String | タスクグループ |
| invokeTarget | String | 呼び出し先 |
| cronExpression | String | Cron式 |
| misfirePolicy | String | ミスファイアポリシー |
| concurrent | String | 並行実行設定 |
| status | String | ステータス |
| nextValidTime | Date | 次回実行予定時刻 |
| createBy | String | 作成者 |
| createTime | Date | 作成日時 |

### 出力先

- 画面表示（TableDataInfo形式）
- Excelファイル（エクスポート時）

## 処理フロー

### 処理シーケンス

```
1. タスク一覧表示
   └─ 検索条件でDBからタスク一覧を取得
   └─ ページネーション適用
   └─ 結果を返却

2. タスク新規登録
   └─ 入力値のバリデーション
      └─ Cron式の有効性チェック
      └─ 呼び出し先のホワイトリストチェック
      └─ 禁止文字列（rmi, ldap, http等）チェック
   └─ DBにタスク情報を保存（status=PAUSE）
   └─ Quartzスケジューラにジョブを登録

3. タスク編集
   └─ 入力値のバリデーション（新規登録と同様）
   └─ DBのタスク情報を更新
   └─ Quartzスケジューラのジョブを更新（削除→再作成）

4. タスク削除
   └─ DBからタスク情報を削除
   └─ Quartzスケジューラからジョブを削除

5. ステータス変更
   └─ 正常（resume）→ Quartzジョブを再開
   └─ 一時停止（pause）→ Quartzジョブを停止

6. 即時実行
   └─ ジョブの存在確認
   └─ JobDataMapにタスク情報を設定
   └─ scheduler.triggerJob()で即時実行
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{操作種別}
    B -->|一覧| C[検索条件取得]
    C --> D[DB検索]
    D --> E[結果返却]

    B -->|新規登録| F[入力値受付]
    F --> G{Cron式有効?}
    G -->|No| H[エラー返却]
    G -->|Yes| I{ホワイトリスト?}
    I -->|No| J[エラー返却]
    I -->|Yes| K{禁止文字列?}
    K -->|Yes| L[エラー返却]
    K -->|No| M[DB保存]
    M --> N[Quartz登録]
    N --> O[成功返却]

    B -->|削除| P[ID取得]
    P --> Q[DB削除]
    Q --> R[Quartz削除]
    R --> S[成功返却]

    B -->|ステータス変更| T[ステータス取得]
    T --> U{正常/停止}
    U -->|正常| V[Quartz再開]
    U -->|停止| W[Quartz停止]
    V --> X[DB更新]
    W --> X
    X --> Y[成功返却]

    E --> Z[終了]
    H --> Z
    J --> Z
    L --> Z
    O --> Z
    S --> Z
    Y --> Z
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-16-01 | 初期ステータス | 新規登録時のステータスは「一時停止」 | タスク新規登録時 |
| BR-16-02 | Cron式検証 | Cron式は有効な形式でなければならない | 登録・編集時 |
| BR-16-03 | ホワイトリスト | 呼び出し先はホワイトリストに登録されたものに限定 | 登録・編集時 |
| BR-16-04 | 禁止文字列 | rmi, ldap, http(s)を含む呼び出し先は禁止 | 登録・編集時 |
| BR-16-05 | DB同期 | タスク変更時はDBとQuartzスケジューラを同期 | 全操作時 |
| BR-16-06 | 起動時初期化 | アプリケーション起動時にDBからタスクを読み込みQuartzに登録 | 起動時 |

### 計算ロジック

#### 次回実行時刻の算出

CronUtils.getNextExecution(cronExpression)を使用してCron式から次回実行時刻を計算。

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 一覧取得 | sys_job | SELECT | タスク一覧を取得 |
| 新規登録 | sys_job | INSERT | タスク情報を保存 |
| 編集 | sys_job | UPDATE | タスク情報を更新 |
| 削除 | sys_job | DELETE | タスク情報を削除 |
| ステータス変更 | sys_job | UPDATE | statusカラムを更新 |

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

#### sys_job

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | job_id, job_name, job_group, invoke_target, cron_expression, misfire_policy, concurrent, status, create_by, create_time | 入力値 | 新規登録 |
| UPDATE | job_name, job_group, invoke_target, cron_expression, misfire_policy, concurrent, status, update_by, update_time | 入力値 | 編集 |
| DELETE | - | WHERE job_id = ? | 削除 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | Cron式エラー | 無効なCron式 | 正しいCron式を入力 |
| - | ホワイトリストエラー | ホワイトリスト外の呼び出し先 | 許可された呼び出し先を使用 |
| - | 禁止文字列エラー | rmi, ldap, http含む呼び出し先 | 禁止文字列を含まない呼び出し先を使用 |
| - | タスク不存在 | 即時実行時にタスクが存在しない | タスクを確認 |
| - | SchedulerException | Quartz操作エラー | システム管理者に連絡 |

### リトライ仕様

特になし

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

- 各操作は@Transactional(rollbackFor = Exception.class)でトランザクション管理
- DB操作とQuartz操作を同一トランザクションで実行
- エラー発生時は全操作をロールバック

## パフォーマンス要件

- 一覧表示：1秒以内にレスポンス
- タスク登録・編集：1秒以内にレスポンス
- 即時実行：非同期実行のため即時レスポンス

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

- Apache Shiroによる権限制御
- 操作ログの記録（@Logアノテーション）
- 呼び出し先のホワイトリスト検証によるRCE防止
- rmi, ldap, http呼び出しの禁止による攻撃ベクター排除

## 備考

- Quartzのジョブキーは「jobId_jobGroup」形式
- ミスファイアポリシーはQuartzのミスファイア処理に対応
- 並行実行禁止設定時はQuartzDisallowConcurrentExecutionアノテーション相当の動作

---

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

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

### 推奨読解順序

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

まず、タスク情報のデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | SysJob.java | `ruoyi-quartz/src/main/java/com/ruoyi/quartz/domain/SysJob.java` | タスクのエンティティクラス。バリデーションアノテーションとgetNextValidTime()に注目 |

**読解のコツ**: `@NotBlank`、`@Size`アノテーションはBean Validationの設定。misfirePolicy、concurrentのデフォルト値にも注意。

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

コントローラーが処理の起点となる。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | SysJobController.java | `ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobController.java` | 各エンドポイントの定義、バリデーションロジック |

**主要処理フロー**:
- **51-59行目**: list() - タスク一覧取得
- **131-163行目**: addSave() - 新規登録（セキュリティチェック含む）
- **179-210行目**: editSave() - 編集（セキュリティチェック含む）
- **94-103行目**: changeStatus() - ステータス変更
- **108-116行目**: run() - 即時実行
- **215-220行目**: checkCronExpressionIsValid() - Cron式検証

#### Step 3: サービス層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ISysJobService.java | `ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/ISysJobService.java` | サービスインターフェース定義 |
| 3-2 | SysJobServiceImpl.java | `ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/impl/SysJobServiceImpl.java` | サービス実装、Quartz連携ロジック |

**主要処理フロー**:
- **39-48行目**: init() - @PostConstructでDB→Quartz同期
- **80-92行目**: pauseJob() - タスク一時停止
- **99-112行目**: resumeJob() - タスク再開
- **156-171行目**: changeStatus() - ステータス変更（内部でpause/resume呼び出し）
- **178-195行目**: run() - 即時実行
- **203-213行目**: insertJob() - 新規登録（DB+Quartz）
- **220-231行目**: updateJob() - 更新（DB+Quartz再作成）

#### Step 4: ユーティリティ・Quartz連携を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | ScheduleUtils.java | `ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/ScheduleUtils.java` | Quartzジョブ作成、ホワイトリストチェック |
| 4-2 | CronUtils.java | `ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/CronUtils.java` | Cron式の検証、次回実行時刻算出 |

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

```
SysJobController
    │
    ├─ list()
    │      └─ ISysJobService.selectJobList()
    │             └─ SysJobMapper.selectJobList()
    │
    ├─ addSave()
    │      ├─ CronUtils.isValid()
    │      ├─ ScheduleUtils.whiteList()
    │      └─ ISysJobService.insertJob()
    │             ├─ SysJobMapper.insertJob()
    │             └─ ScheduleUtils.createScheduleJob()
    │                    └─ scheduler.scheduleJob()
    │
    ├─ editSave()
    │      └─ ISysJobService.updateJob()
    │             ├─ SysJobMapper.updateJob()
    │             └─ updateSchedulerJob()
    │                    ├─ scheduler.deleteJob()
    │                    └─ ScheduleUtils.createScheduleJob()
    │
    ├─ changeStatus()
    │      └─ ISysJobService.changeStatus()
    │             ├─ resumeJob() / pauseJob()
    │             │      └─ scheduler.resumeJob() / pauseJob()
    │             └─ SysJobMapper.updateJob()
    │
    └─ run()
           └─ ISysJobService.run()
                  └─ scheduler.triggerJob()
```

### データフロー図

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

タスク情報    ───▶ Controller         ───▶ AjaxResult
(jobName,          ↓                        (成功/エラー)
 cronExp,          バリデーション
 invokeTarget)     ↓
                   Service
                   ↓
              ┌────┴────┐
              ↓         ↓
           Mapper    Quartz
              ↓         ↓
           sys_job   Scheduler
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| SysJobController.java | `ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/` | コントローラー | HTTPリクエストのハンドリング |
| SysJob.java | `ruoyi-quartz/src/main/java/com/ruoyi/quartz/domain/` | エンティティ | タスクのデータモデル |
| ISysJobService.java | `ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/` | インターフェース | サービス層の契約定義 |
| SysJobServiceImpl.java | `ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/impl/` | サービス実装 | ビジネスロジック |
| SysJobMapper.java | `ruoyi-quartz/src/main/java/com/ruoyi/quartz/mapper/` | Mapper | データアクセス層インターフェース |
| SysJobMapper.xml | `ruoyi-quartz/src/main/resources/mapper/quartz/` | MyBatis XML | SQL定義 |
| ScheduleUtils.java | `ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/` | ユーティリティ | Quartzジョブ操作 |
| CronUtils.java | `ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/` | ユーティリティ | Cron式操作 |
| AbstractQuartzJob.java | `ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/` | 抽象クラス | Quartzジョブの基底クラス |
| QuartzJobExecution.java | `ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/` | 実装クラス | Quartzジョブ実行クラス |
