|
| 1 | +# Refactoring Plan: Runner / Job Actor 分離 |
| 2 | + |
| 3 | +**Status: COMPLETED** |
| 4 | + |
| 5 | +## 現状の問題 |
| 6 | + |
| 7 | +scheduler.rs に責務が混在している: |
| 8 | + |
| 9 | +``` |
| 10 | +Scheduler Actor |
| 11 | +├── Tick (1秒ごと cron評価) |
| 12 | +├── try_sync_job() ← Tick をブロック |
| 13 | +├── Concurrency 制御 |
| 14 | +├── Executor spawn |
| 15 | +├── job_handles 管理 |
| 16 | +└── JobCompleted 処理 |
| 17 | +``` |
| 18 | + |
| 19 | +問題点: |
| 20 | +1. **Sync が Tick をブロック** - git sync がスケジューラのイベントループを止める |
| 21 | +2. **ConfigUpdate で job_handles 孤児化** - 削除されたジョブのタスクが残る |
| 22 | +3. **Wait モードが無制限キュー** - バックプレッシャーなし |
| 23 | +4. **Job Actor 不在** - Executor は単なる async task |
| 24 | + |
| 25 | +## 提案: Runner / Job Actor 分離 |
| 26 | + |
| 27 | +``` |
| 28 | +┌─────────────────────────────────────────────────────────────────┐ |
| 29 | +│ ROOT RUNNER │ |
| 30 | +│ 責務: ライフサイクル管理 │ |
| 31 | +├─────────────────────────────────────────────────────────────────┤ |
| 32 | +│ • CLI解析 │ |
| 33 | +│ • Git pull cycle (async task) │ |
| 34 | +│ • Config parse → Job Actor 生成/更新/削除 │ |
| 35 | +│ • Graceful shutdown (SIGTERM → 全 Actor に通知) │ |
| 36 | +│ • グローバル env 解決 │ |
| 37 | +└──────────────────────────┬──────────────────────────────────────┘ |
| 38 | + │ spawn / update / kill |
| 39 | + ▼ |
| 40 | +┌─────────────────────────────────────────────────────────────────┐ |
| 41 | +│ JOB ACTOR (per job) │ |
| 42 | +│ 責務: 単一ジョブの完全な自律制御 │ |
| 43 | +├─────────────────────────────────────────────────────────────────┤ |
| 44 | +│ • 自身の Tick (毎秒 cron 評価) │ |
| 45 | +│ • Jitter 適用 │ |
| 46 | +│ • Concurrency 制御 (状態機械) │ |
| 47 | +│ • Git sync (自分のディレクトリのみ) │ |
| 48 | +│ • Command 実行 + timeout │ |
| 49 | +│ • Retry (backoff + jitter) │ |
| 50 | +│ • Log 出力・ローテーション │ |
| 51 | +│ • Webhook 送信 │ |
| 52 | +│ • Job 固有 env 解決 │ |
| 53 | +└─────────────────────────────────────────────────────────────────┘ |
| 54 | +``` |
| 55 | + |
| 56 | +## 通信プロトコル |
| 57 | + |
| 58 | +``` |
| 59 | + ┌──────────────────────────────────────────────────────┐ |
| 60 | + │ Runner Actor │ |
| 61 | + │ │ |
| 62 | + │ ┌─────────────┐ ┌─────────────────────────┐ │ |
| 63 | + SIGTERM ──────▶│ │ Signal Loop │ │ Git Poll Loop │ │ |
| 64 | + │ └──────┬──────┘ │ fetch → parse config │ │ |
| 65 | + │ │ └───────────┬─────────────┘ │ |
| 66 | + │ │ │ │ |
| 67 | + │ │ ┌────────────────────┘ │ |
| 68 | + │ │ │ │ |
| 69 | + │ ▼ ▼ │ |
| 70 | + │ ┌─────────────────────────────────────────────┐ │ |
| 71 | + │ │ Lifecycle Manager │ │ |
| 72 | + │ │ HashMap<JobId, Addr<JobActor>> │ │ |
| 73 | + │ └─────────────────────────────────────────────┘ │ |
| 74 | + └───────────────────────┬──────────────────────────────┘ |
| 75 | + │ |
| 76 | + ┌─────────────────────────────┼─────────────────────────────┐ |
| 77 | + │ │ │ |
| 78 | + ▼ ▼ ▼ |
| 79 | + ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ |
| 80 | + │ Job Actor [A] │ │ Job Actor [B] │ │ Job Actor [C] │ |
| 81 | + └─────────────────┘ └─────────────────┘ └─────────────────┘ |
| 82 | +``` |
| 83 | + |
| 84 | +### メッセージ一覧 |
| 85 | + |
| 86 | +``` |
| 87 | +Runner → Job Actor: |
| 88 | + ┌─────────────────┬────────────────────────────────────────────────┐ |
| 89 | + │ Update(Job) │ config変更時。Actor は次の tick から新設定で動作 │ |
| 90 | + │ Shutdown │ job削除時。即座に停止 │ |
| 91 | + │ GracefulStop │ SIGTERM時。現在の実行完了後に停止 │ |
| 92 | + └─────────────────┴────────────────────────────────────────────────┘ |
| 93 | +
|
| 94 | +Job Actor → Runner: |
| 95 | + (明示的メッセージなし - xtra の Addr で停止検知) |
| 96 | +``` |
| 97 | + |
| 98 | +### Supervision |
| 99 | + |
| 100 | +``` |
| 101 | +Runner の監視責務: |
| 102 | + - 各 Actor の Addr<JobActor> を保持 |
| 103 | + - 予期せぬ停止を検知 → 同じ設定で再spawn |
| 104 | + - GracefulStop 後は addr.stopped() で完了待機 |
| 105 | +``` |
| 106 | + |
| 107 | +### ログの責務 |
| 108 | + |
| 109 | +``` |
| 110 | +Runner がログ: |
| 111 | + - 設定エラー (cron パース失敗、必須フィールド欠落など) |
| 112 | + - Job Actor の spawn/停止/再spawn |
| 113 | + - Git pull の結果 |
| 114 | +
|
| 115 | +Job Actor がログ: |
| 116 | + - コマンド実行結果 (log_file へ) |
| 117 | + - sync 失敗、retry、timeout (stderr へ) |
| 118 | +``` |
| 119 | + |
| 120 | +### ライフサイクルイベント |
| 121 | + |
| 122 | +``` |
| 123 | +[起動時] |
| 124 | + Runner: config parse → 有効な job ごとに spawn(Job) → HashMap に登録 |
| 125 | +
|
| 126 | +[git pull 後] |
| 127 | + Runner: 新旧 config を diff |
| 128 | + - 新規 job → spawn(Job) |
| 129 | + - 既存 job → send Update(Job) |
| 130 | + - 削除 job → send Shutdown, HashMap から削除 |
| 131 | + - 無効 job → スキップ + error log |
| 132 | +
|
| 133 | +[SIGTERM] |
| 134 | + Runner: 全 Job Actor に GracefulStop → 完了待ち → exit |
| 135 | +``` |
| 136 | + |
| 137 | +## 設計原則 |
| 138 | + |
| 139 | +- **Job Actor は停止しない** - コマンド失敗、sync失敗、timeout は状態遷移であり Actor の停止理由にならない |
| 140 | +- **停止するのは Runner からの指示のみ** - Shutdown / GracefulStop メッセージ |
| 141 | +- **ジョブは独立** - 1つのジョブの設定エラーが他のジョブに影響しない |
| 142 | + - 起動時: 無効なジョブはスキップ + エラーログ、有効なジョブは起動 |
| 143 | + - 更新時: 無効なジョブはスキップ + エラーログ、有効なジョブは更新 |
| 144 | + |
| 145 | +## Job Actor 状態遷移 |
| 146 | + |
| 147 | +``` |
| 148 | + ┌────────┐ |
| 149 | + ─────────│ Idle │◀────────────────────────────────────┐ |
| 150 | + └───┬────┘ │ |
| 151 | + │ [cron due] │ |
| 152 | + ▼ │ |
| 153 | + ┌────────┐ │ |
| 154 | + │Syncing │── fail ──▶ [retry next tick] ──────┤ |
| 155 | + └───┬────┘ │ |
| 156 | + │ [ok] │ |
| 157 | + ▼ │ |
| 158 | + ┌────────┐ │ |
| 159 | + │Running │── success ─────────────────────────▶│ |
| 160 | + └───┬────┘ │ |
| 161 | + │ [fail + retry left] │ |
| 162 | + ▼ │ |
| 163 | + ┌────────┐ │ |
| 164 | + │Backoff │── delay ──▶ Running ───────────────▶│ |
| 165 | + └────────┘ |
| 166 | +``` |
| 167 | + |
| 168 | +## ファイル分割案 |
| 169 | + |
| 170 | +``` |
| 171 | +src/ |
| 172 | +├── main.rs # CLI, bootstrap, signal handling |
| 173 | +├── actor/ |
| 174 | +│ ├── runner/ # Runner Actor |
| 175 | +│ │ ├── mod.rs # Actor 定義、メッセージ |
| 176 | +│ │ ├── git_poll.rs # git fetch/reset ループ |
| 177 | +│ │ └── lifecycle.rs # Job Actor の生成/削除 |
| 178 | +│ └── job/ # Job Actor |
| 179 | +│ ├── mod.rs # Actor 定義、状態機械 |
| 180 | +│ ├── tick.rs # cron評価、jitter |
| 181 | +│ ├── executor.rs # command実行、retry、timeout |
| 182 | +│ └── logger.rs # log出力、rotation |
| 183 | +├── config.rs # (変更なし) |
| 184 | +├── git.rs # (変更なし) |
| 185 | +└── env.rs # (変更なし) |
| 186 | +``` |
| 187 | + |
| 188 | +各 actor ディレクトリを見ればその actor の責務が完結する。 |
| 189 | + |
| 190 | +## 実装順序 |
| 191 | + |
| 192 | +1. actor/job/mod.rs - Job Actor の骨格 |
| 193 | +2. actor/job/* - Scheduler から job 単位ロジックを抽出 |
| 194 | +3. actor/runner/mod.rs - Runner Actor の骨格 |
| 195 | +4. actor/runner/lifecycle.rs - Job Actor の生成/更新/削除 |
| 196 | +5. actor/runner/git_poll.rs - git fetch ループを移動 |
| 197 | +6. main.rs - Runner Actor を起動するだけに簡素化 |
0 commit comments