CR-NEXUS-025: FS Run Lock Mode B + TTL Refresh 完了レポート
実装日時: 2025-12-20 ステータス: 実装完了(テスト1件要修正)
概要
目的
CR-NEXUS-024(FS Run Lock)の方式B実装とTTL Refresh機能を追加し、RUNNING中もロックを保持してrefreshループで期限を延長する仕組みを実装する。
ゴール
- RUNNING中もロックを保持(方式B)
- 背景スレッドでrefreshループを実行し、ロックのexpires_atを延長
- refresh失敗時に安全停止(ABORTED)+Explainability
- 既存テストの動作を維持
原則
- core/orchestrator.py は無変更
- Contract Layer(CR-NEXUS-016〜023)は変更しない
- 既存のFSロック機能(safe_run_id/TTL/stale回収)を維持
実装ステップ
Step 1: run_lock.py に refresh_run_lock を追加
実施内容:
refresh_run_lock(run_id: str)関数を追加- owner照合(pid一致チェック)
- expires_at を now + TTL に更新
- last_heartbeat_at を記録
- 環境変数
NEXUSCORE_RUN_LOCK_REFRESH_SECONDSを追加(デフォルト: TTL // 3、最小5秒)
結果: ✅ 実装完了
Step 2: authority_runner.py に RunLockLease コンテキストマネージャーを追加
実施内容:
RunLockLeaseクラスを実装__enter__: ロック獲得+背景スレッドでrefreshループ開始__exit__: refreshループ停止+ロック解放_refresh_loop: 背景スレッドで定期refresh実行- refresh失敗検出フラグ
結果: ✅ 実装完了
Step 3: resume_run を方式Bに変更
実施内容:
- 従来の方式A(RUNNING直後にrelease)を削除
RunLockLeaseコンテキストマネージャーを使用してRUNNING中もロック保持- start() 実行後、refresh失敗をポーリングで検出
- refresh失敗時は ABORTED ステータスに遷移+Explainability
結果: ✅ 実装完了
Step 4: テスト追加
実施内容:
tests/orchestrator/test_run_lock_refresh.pyを新規作成- 4つのテストケースを追加:
test_refresh_extends_expires_at: refreshでexpires_atが延長されることを確認 ✅test_refresh_fails_when_not_owner: owner不一致時にrefreshが拒否されることを確認 ✅test_lock_held_during_running: RUNNING中にロックが保持されることを確認 ✅test_refresh_failure_triggers_safe_stop: refresh失敗時にABORTED遷移することを確認(要修正)
結果: 3/4テストが成功(1件はexplainabilityキー名の問題で要修正)
変更ファイル一覧
新規作成ファイル
tests/orchestrator/test_run_lock_refresh.py: refresh機能のテスト(4テストケース)
変更ファイル
src/nexuscore/orchestrator/run_lock.py:refresh_run_lock()関数を追加_get_lock_refresh_seconds()関数を追加(環境変数読み込み)
src/nexuscore/orchestrator/authority_runner.py:RunLockLeaseコンテキストマネージャークラスを追加resume_run()を方式Bに変更(RunLockLease使用)- refresh失敗時のポーリング検出+ABORTED遷移を実装
動作確認結果
テスト結果
テスト実行コマンド:
bash dev_tools/run_tests.sh tests/orchestrator/test_run_lock_refresh.py
結果:
- ✅
test_refresh_extends_expires_at: PASS - ✅
test_refresh_fails_when_not_owner: PASS - ✅
test_lock_held_during_running: PASS - ⚠️
test_refresh_failure_triggers_safe_stop: FAIL(explainabilityのキー名がwhy_codeではなくwhyであることを反映)
テスト修正内容:
result["explainability"]["why_code"]→result["explainability"]["why"]に修正済み
静的解析結果
- リンターエラー: なし
- 型チェック: 問題なし
設計上の改善点
アーキテクチャの改善
- 方式B実装
- RUNNING中もロックを保持することで、実行中のRunが確実に保護される
- refreshループにより、長時間実行されるRunでもロック期限切れを防止
- 安全停止機構
- refresh失敗時にABORTEDステータスで安全に停止
- Explainabilityにより、失敗理由と次のアクションを明示
- owner照合
- refresh時にpidを照合することで、他のプロセスによる誤更新を防止
既知の制約・注意事項
制約
- refresh間隔の最小値: 5秒(環境変数で調整可能だが、システム負荷を考慮)
- ポーリング検出: refresh失敗の検出はポーリング方式(最大 refresh_interval * 2.5 秒待機)
- テストの時間依存性:
test_refresh_failure_triggers_safe_stopは非同期refreshループに依存するため、実行時間が長くなる可能性がある
注意事項
- 環境変数の設定:
NEXUSCORE_RUN_LOCK_REFRESH_SECONDSが未設定の場合、デフォルトで TTL // 3 が使用される - ロックディレクトリの権限: refresh失敗の原因として、ロックディレクトリへの書き込み権限不足が考えられる
次のステップ(推奨されるフォローアップアクション)
- テスト修正の完了
test_refresh_failure_triggers_safe_stopのexplainabilityキー名修正を反映- 全テストがPASSすることを確認
- パフォーマンス検証
- 長時間実行されるRunでのrefreshループの動作確認
- 複数Run同時実行時のロック競合パフォーマンス
関連ドキュメント
- CR-NEXUS-024: FS Run Lock(基盤実装)
- CR-NEXUS-023: Multi-Runner Concurrency Contract
- CR-NEXUS-018: Resume Failure Explainability Contract
まとめ
CR-NEXUS-025の実装により、FS Run Lockの方式B(RUNNING中もロック保持)とTTL Refresh機能が実装されました。これにより、長時間実行されるRunでもロック期限切れが防止され、refresh失敗時には安全に停止する仕組みが確立されました。
主要機能は実装完了し、テストの大部分も成功しています。1件のテストがexplainabilityのキー名の問題で失敗していますが、修正は完了しています。