mirror of
https://github.com/AstrBotDevs/AstrBot
synced 2026-07-15 17:30:13 +08:00
* fix: exit MCP anyio contexts in the lifecycle task on disable #9070 moved MCP shutdown cleanup into the per-server lifecycle task so that the anyio cancel scopes entered in connect_to_server() are exited from the task that entered them. Running the cleanup through asyncio.shield() defeats that: shield wraps the coroutine in a new task, so disabling a server still fails with "Attempted to exit cancel scope in a different task than it was entered in" and leaves the scope state corrupted -- the failure mode behind the CPU spin reported in #9068. Await _terminate_mcp_client() directly instead. The graceful disable path has no cancellation in flight, and on forced shutdown the lifecycle task still runs its finally block in-task, so the shield only served to break task affinity. Closes #9068 * fix: absorb late cancellations during MCP shutdown cleanup A cancellation delivered while the lifecycle task is already running its finally-block cleanup would abort _terminate_mcp_client() halfway, stranding the runtime entry and the MCP transport. Retry the cleanup in the same task and uncancel() the absorbed request instead, so a forced shutdown can no longer skip it. * fix: guard Task.uncancel() for Python 3.10 runtimes Task.uncancel() only exists on Python 3.11+. On 3.10 absorbing the CancelledError is sufficient, so skip the call when unavailable.