auto-sync: 2026-05-19 23:07:37
This commit is contained in:
+58
-1
@@ -40,6 +40,9 @@ class Ticker:
|
||||
max_dispatch_per_tick: int = 3,
|
||||
claim_timeout_minutes: float = 5.0,
|
||||
default_task_timeout_minutes: float = 30.0,
|
||||
health_checker: Optional[Any] = None,
|
||||
inbox_watcher: Optional[Any] = None,
|
||||
experience_distiller: Optional[Any] = None,
|
||||
):
|
||||
"""
|
||||
Args:
|
||||
@@ -76,6 +79,14 @@ class Ticker:
|
||||
# 当前项目 ID(_dispatch_pending 需要)
|
||||
self._current_project_id: Optional[str] = None
|
||||
|
||||
# 集成模块
|
||||
self.health_checker = health_checker
|
||||
self.inbox_watcher = inbox_watcher
|
||||
self.experience_distiller = experience_distiller
|
||||
|
||||
# InboxWatcher 即时 tick 事件
|
||||
self._inbox_event: asyncio.Event = asyncio.Event()
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 生命周期
|
||||
# ------------------------------------------------------------------
|
||||
@@ -85,12 +96,30 @@ class Ticker:
|
||||
if self._running:
|
||||
return
|
||||
self._running = True
|
||||
|
||||
# 启动 InboxWatcher
|
||||
if self.inbox_watcher:
|
||||
try:
|
||||
await self.inbox_watcher.start()
|
||||
logger.info("InboxWatcher started")
|
||||
except Exception:
|
||||
logger.exception("Failed to start InboxWatcher")
|
||||
|
||||
self._task = asyncio.create_task(self._loop())
|
||||
logger.info("Ticker started (interval=%.1fs)", self.tick_interval)
|
||||
|
||||
async def stop(self) -> None:
|
||||
"""停止 tick 循环"""
|
||||
self._running = False
|
||||
|
||||
# 停止 InboxWatcher
|
||||
if self.inbox_watcher:
|
||||
try:
|
||||
await self.inbox_watcher.stop()
|
||||
logger.info("InboxWatcher stopped")
|
||||
except Exception:
|
||||
logger.exception("Failed to stop InboxWatcher")
|
||||
|
||||
if self._task:
|
||||
self._task.cancel()
|
||||
try:
|
||||
@@ -126,8 +155,16 @@ class Ticker:
|
||||
self._running = False
|
||||
break
|
||||
|
||||
# 等待下一个 tick,但 InboxWatcher 事件可提前唤醒
|
||||
try:
|
||||
await asyncio.sleep(self.tick_interval)
|
||||
await asyncio.wait_for(
|
||||
self._inbox_event.wait(),
|
||||
timeout=self.tick_interval,
|
||||
)
|
||||
self._inbox_event.clear()
|
||||
logger.debug("Immediate tick triggered by inbox event")
|
||||
except asyncio.TimeoutError:
|
||||
pass # 正常超时,继续下一次 tick
|
||||
except asyncio.CancelledError:
|
||||
return
|
||||
|
||||
@@ -241,6 +278,26 @@ class Ticker:
|
||||
# 8. 扫描后状态
|
||||
result["summary_after"] = queries.task_summary()
|
||||
|
||||
# 9. HealthChecker 僵尸检测
|
||||
if self.health_checker:
|
||||
try:
|
||||
health_result = self.health_checker.check(
|
||||
project_id, db_path, self._tick_count)
|
||||
result["health"] = health_result
|
||||
if not health_result.get("healthy", True):
|
||||
logger.warning("Health check: %s unhealthy (zombie=%s)",
|
||||
project_id, health_result.get("zombie"))
|
||||
except Exception:
|
||||
logger.exception("HealthChecker error for %s", project_id)
|
||||
|
||||
# 10. ExperienceDistiller 经验蒸馏
|
||||
if self.experience_distiller:
|
||||
try:
|
||||
distilled = self._distill_completed_tasks(db_path, project_id)
|
||||
result["distilled"] = distilled
|
||||
except Exception:
|
||||
logger.exception("ExperienceDistiller error for %s", project_id)
|
||||
|
||||
return result
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user