diff --git a/src/daemon/ticker.py b/src/daemon/ticker.py index 5576488..38880ba 100644 --- a/src/daemon/ticker.py +++ b/src/daemon/ticker.py @@ -640,7 +640,7 @@ class Ticker: reclaimed: List[str] = [] now = datetime.utcnow() # UTC,与 SQLite datetime('now') 一致 - # claimed 超时 → 重置为 pending + # claimed 超时 → 重置为 pending(如果 retry_count >= 3 则升级庞统) claimed = queries.tasks_by_status("claimed") for task in claimed: if not task.claimed_at: @@ -649,20 +649,37 @@ class Ticker: claimed_time = datetime.fromisoformat(task.claimed_at) elapsed = (now - claimed_time).total_seconds() / 60.0 if elapsed > self.claim_timeout_minutes: - conn = get_connection(db_path) - try: - ok = self._transition_status( - conn, task.id, "pending", - agent="daemon", - detail={"reason": "claim_timeout", - "elapsed_minutes": round(elapsed, 1)}, - ) - if ok: + retry_count = getattr(task, 'retry_count', 0) or 0 + # 司马懿建议:复用 retry_count,>=3 则升级庞统 + if retry_count >= 3: + conn = get_connection(db_path) + try: + self._transition_status( + conn, task.id, "escalated", + agent="daemon", + detail={"reason": "claim_timeout_no_taker", + "retry_count": retry_count}, + ) reclaimed.append(task.id) - logger.info("Reclaimed %s: claimed → pending (timeout %.1fm)", - task.id, elapsed) - finally: - conn.close() + logger.warning("Escalated %s: no taker after %d broadcasts", + task.id, retry_count) + finally: + conn.close() + else: + conn = get_connection(db_path) + try: + ok = self._transition_status( + conn, task.id, "pending", + agent="daemon", + detail={"reason": "claim_timeout", + "elapsed_minutes": round(elapsed, 1)}, + ) + if ok: + reclaimed.append(task.id) + logger.info("Reclaimed %s: claimed → pending (timeout %.1fm)", + task.id, elapsed) + finally: + conn.close() except (ValueError, TypeError): pass