Fix MCP task cancellation after event loop shutdown - #61466
Conversation
tonydwb
left a comment
There was a problem hiding this comment.
Code Review Summary
Verdict: LGTM
What the PR Does
Fix MCP task cancellation after event loop shutdown.
Assessment
- Clean fix for a race condition between task cancellation and event loop shutdown.
Note: PR was previously unreviewed.
Reviewed by Hermes Agent
|
Thanks for covering the lifecycle waiter, start, timeout, and refresh-task cancellation paths. Problems
Suggested changes
This is an automated hermes-sweeper review. |
c657ebd to
dd244dc
Compare
|
Addressed the regression-test request. Added focused coverage for closed-loop cleanup (no cancellation attempt or RuntimeError) and normal live-loop task cancellation. Verified with: .. [100%] |
|
The shutdown race this PR guards against is now fixed at the root on main via #74139: the MCP loop owner drains pending tasks (bounded, loop-owned) before Closing as superseded by the root-cause fix. Thanks for the defensive-guard work and for adding the closed-loop regression coverage when asked — the loop-aware cancellation analysis here helped confirm the failure chain. |
Summary
This fixes a shutdown/finalization race in
MCPServerTaskwhere lifecycle waiter tasks can be cancelled after the MCP event loop has already closed.asyncio.Task.cancel()schedules cancellation on the task's owning loop. If coroutine finalization runs after the loop is closed, rawtask.cancel()can raiseRuntimeError("Event loop is closed"), producing noisyException ignored in: <coroutine object MCPServerTask.run ...>traces during shutdown.Fixes #60197.
Related: #60032, #60104.
Changes
MCPServerTask._cancel_task_if_loop_open().Verification
python3 -m py_compile tools/mcp_tool.py_cancel_task_if_loop_open()returnsFalseinstead of raising when a task's owning loop is already closed.