From dc3f757aec9f390b37c63109ba1ca8fd0d404096 Mon Sep 17 00:00:00 2001 From: cfdaily Date: Tue, 26 May 2026 20:29:07 +0800 Subject: [PATCH] auto-sync: 2026-05-26 20:29:07 --- src/daemon/spawner.py | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/src/daemon/spawner.py b/src/daemon/spawner.py index e595062..08f3499 100644 --- a/src/daemon/spawner.py +++ b/src/daemon/spawner.py @@ -356,17 +356,21 @@ curl -X POST http://{self.api_host}:{self.api_port}/api/projects/{project_id}/ta Raises: AgentBusyError: agent 被 counter 占用或冷却中 """ - # ── v2.7.2: counter 检查 + acquire ── - if self.counter: - if not await self.counter.can_acquire(agent_id): - raise AgentBusyError(agent_id) - await self.counter.acquire(agent_id) + # ── v2.7.2 → v2.1: 先分配 session_id,再 counter acquire ── - # ── v2.7.2: session state 检查(防外部占用)── + # 1. 分配 session_id(纯计算,无 IO) + if use_main_session: + session_id = None + elif reuse_session_id: + session_id = reuse_session_id + else: + session_id = str(uuid.uuid4()) + _sid_key = session_id or "main" # counter 用的 key + + # 2. session state 检查(main session 防外部占用) if use_main_session: session_state = self._check_session_state(agent_id) if session_state.get("lock_pid_alive"): - # main session 被 webchat/Control UI/cron 占用 logger.info("Spawn skipped: %s main session locked by PID %d", agent_id, session_state.get("lock_pid")) raise AgentBusyError(f"{agent_id}: session locked by PID {session_state.get('lock_pid')}") @@ -377,24 +381,22 @@ curl -X POST http://{self.api_host}:{self.api_port}/api/projects/{project_id}/ta logger.info("Spawn skipped: %s compacting", agent_id) raise AgentBusyError(f"{agent_id}: compacting") - # Session 策略:main > reuse > new - if use_main_session: - session_id = None - elif reuse_session_id: - session_id = reuse_session_id - else: - session_id = str(uuid.uuid4()) + # 3. counter acquire(per session key 粒度) + if self.counter: + if not await self.counter.can_acquire(agent_id, _sid_key): + raise AgentBusyError(agent_id) + await self.counter.acquire(agent_id, _sid_key) if self.dry_run: - logger.info("[DRY RUN] Would spawn agent %s (session=%s)", agent_id, session_id or "main") - self._register_session(session_id or "main", agent_id, task_id, pid=None) - return session_id or "main" + logger.info("[DRY RUN] Would spawn agent %s (session=%s)", agent_id, _sid_key) + self._register_session(_sid_key, agent_id, task_id, pid=None) + return _sid_key - # ── v2.7.2: wrapped_on_complete 保证 counter release ── + # 4. wrapped_on_complete 保证 counter release(闭包捕获 _sid_key) async def _wrapped_on_complete(aid, outcome): try: if self.counter: - self.counter.release(aid) + self.counter.release(aid, _sid_key) finally: if on_complete: try: