# バッチ設計書 20-Scheduler

## 概要

本ドキュメントは、定期実行タスクを管理するスケジューラーモジュールの設計書です。インターバルベースでタスクを登録・実行するランタイムコンポーネントです。

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

このモジュールは、OpenCodeアプリケーション内で定期的に実行されるタスクを管理するスケジューラーです。タスクの登録、実行、クリーンアップを提供し、インスタンススコープとグローバルスコープの両方をサポートします。

**業務上の目的・背景**：OpenCodeアプリケーションでは、キャッシュクリア、ヘルスチェック、統計収集など、定期的に実行する必要があるバックグラウンドタスクがあります。このスケジューラーにより、これらのタスクを一元管理し、適切なライフサイクル制御（インスタンス終了時のクリーンアップ等）を実現します。

**バッチの実行タイミング**：アプリケーション起動時にタスクが登録され、指定されたインターバルで継続的に実行されます。

**主要な処理内容**：
1. タスクの登録（register関数）
2. 即時実行と定期実行の設定
3. インスタンススコープ/グローバルスコープの管理
4. インスタンス終了時のタイマークリーンアップ
5. エラーハンドリングとログ出力

**前後の処理との関連**：Instance.stateを使用してインスタンスライフサイクルと連携します。各タスクは独立して実行され、エラーが発生しても他のタスクには影響しません。

**影響範囲**：OpenCodeアプリケーションのランタイム動作、登録されたタスクの実行

## バッチ種別

ランタイム / スケジューラー / バックグラウンドタスク管理

## 実行スケジュール

| 項目 | 内容 |
|-----|------|
| 実行頻度 | タスクごとのインターバル設定 |
| 実行時刻 | タスク登録時から継続 |
| 実行曜日 | - |
| 実行日 | - |
| トリガー | タスク登録（register呼び出し） |

## 実行条件

### 前提条件

| 条件 | 説明 |
|-----|------|
| OpenCodeランタイム | アプリケーションが起動していること |
| Instance.state | インスタンス状態管理が初期化されていること |
| Log.create | ログシステムが利用可能であること |

### 実行可否判定

- タスク登録時に即座に初回実行
- グローバルスコープのタスクは重複登録を防止

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | デフォルト値 | 説明 |
|-------------|-----|-----|-------------|------|
| task.id | string | Yes | - | タスクの一意識別子 |
| task.interval | number | Yes | - | 実行間隔（ミリ秒） |
| task.run | () => Promise<void> | Yes | - | 実行する非同期関数 |
| task.scope | "instance" \| "global" | No | "instance" | タスクのスコープ |

### 入力データソース

該当なし（プログラマティックなタスク登録）

## 出力仕様

### 出力データ

| 出力先 | 形式 | 説明 |
|-------|------|------|
| ログ | structured log | タスク実行ログ（開始、エラー） |

### 出力ファイル仕様

ファイル出力はありません。

## 処理フロー

### 処理シーケンス

```
1. タスク登録（register呼び出し）
   └─ スコープ判定（instance/global）
2. 重複チェック
   └─ グローバルスコープ: 既存タスクがあればスキップ
   └─ インスタンススコープ: 既存タイマーをクリア
3. タスク保存
   └─ tasksマップに登録
4. 即時実行
   └─ run(task)を呼び出し
5. インターバル設定
   └─ setIntervalでタイマー登録
   └─ timer.unref()でプロセス終了をブロックしない
6. タイマー保存
   └─ timersマップに登録
```

### フローチャート

```mermaid
flowchart TD
    A[register呼び出し] --> B{スコープ判定}
    B -->|global| C{既存タスク?}
    B -->|instance| D{既存タイマー?}
    C -->|Yes| E[スキップ]
    C -->|No| F[タスク登録]
    D -->|Yes| G[タイマークリア]
    D -->|No| F
    G --> F
    F --> H[即時実行]
    H --> I[setInterval設定]
    I --> J[timer.unref]
    J --> K[タイマー登録]
    K --> L[完了]
    E --> L
```

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

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

本モジュールはデータベースを直接操作しません。

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

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | タスク実行エラー | task.run()が例外をスロー | エラーログ出力、タスク継続 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0（自動リトライなし） |
| リトライ間隔 | 次回インターバルで再実行 |
| リトライ対象エラー | すべてのエラー |

### 障害時対応

タスク実行時のエラーはキャッチされ、ログに出力されます。エラーが発生しても次回のインターバルで再度実行されます。

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

| 項目 | 内容 |
|-----|------|
| トランザクション範囲 | 各タスク実行単位 |
| コミットタイミング | タスク完了時 |
| ロールバック条件 | タスク内部で処理 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定タスク数 | 数十タスク |
| 目標実行時間 | タスクごとに異なる |
| メモリ使用量上限 | Map構造による軽量な管理 |

## 排他制御

- グローバルスコープのタスクは重複登録を防止
- インスタンススコープのタスクは同一IDで再登録時に既存タイマーをクリア

## ログ出力

| ログ種別 | 出力タイミング | 出力内容 |
|---------|--------------|---------|
| 開始ログ | タスク実行時 | "run", { id: task.id } |
| エラーログ | エラー発生時 | "run failed", { id: task.id, error } |

## 監視・アラート

| 監視項目 | 閾値 | アラート先 |
|---------|-----|----------|
| - | - | - |

アプリケーション内部のモジュールのため、個別の監視は設定されていません。

## 備考

- namespace `Scheduler`としてエクスポート
- `Instance.state`を使用してインスタンスライフサイクルと連携
- インスタンス終了時は全タイマーがclearIntervalで解放
- `timer.unref()`によりNode.jsプロセスの終了をブロックしない
- sharedオブジェクトでグローバルスコープのタスクを管理
- エラーは`.catch()`でキャッチされ、ログ出力後も処理継続
- Log.create({ service: "scheduler" })でサービス名付きログを使用
