mirror of
https://github.com/HKUDS/nanobot.git
synced 2026-08-08 05:18:49 +03:00
fix(gateway): make resource teardown cancellation-safe
This commit is contained in:
@@ -55,6 +55,62 @@ class TestHandleStop:
|
||||
out = await cmd_stop(ctx)
|
||||
assert "No active task" in out.content
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_close_mcp_cancels_active_turn_before_resources(self):
|
||||
loop, _bus = _make_loop()
|
||||
events: list[str] = []
|
||||
|
||||
async def active_turn():
|
||||
try:
|
||||
await asyncio.sleep(60)
|
||||
except asyncio.CancelledError:
|
||||
events.append("turn_cancelled")
|
||||
raise
|
||||
|
||||
task = asyncio.create_task(active_turn())
|
||||
await asyncio.sleep(0)
|
||||
loop._active_tasks["test:c1"] = {task}
|
||||
|
||||
async def close_subagents():
|
||||
events.append("resources_closed")
|
||||
|
||||
loop.subagents.close = close_subagents
|
||||
loop._exec_session_manager.close_all = AsyncMock()
|
||||
with patch("nanobot.agent.loop.agent_context.close_mcp", AsyncMock()):
|
||||
await loop.close_mcp()
|
||||
|
||||
assert events == ["turn_cancelled", "resources_closed"]
|
||||
assert task.cancelled()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_close_mcp_serializes_duplicate_cleanup(self):
|
||||
loop, _bus = _make_loop()
|
||||
entered = asyncio.Event()
|
||||
release = asyncio.Event()
|
||||
concurrent = 0
|
||||
max_concurrent = 0
|
||||
|
||||
async def close_subagents():
|
||||
nonlocal concurrent, max_concurrent
|
||||
concurrent += 1
|
||||
max_concurrent = max(max_concurrent, concurrent)
|
||||
entered.set()
|
||||
await release.wait()
|
||||
concurrent -= 1
|
||||
|
||||
loop.subagents.close = close_subagents
|
||||
loop._exec_session_manager.close_all = AsyncMock()
|
||||
with patch("nanobot.agent.loop.agent_context.close_mcp", AsyncMock()):
|
||||
first = asyncio.create_task(loop.close_mcp())
|
||||
await entered.wait()
|
||||
second = asyncio.create_task(loop.close_mcp())
|
||||
await asyncio.sleep(0)
|
||||
assert not second.done()
|
||||
release.set()
|
||||
await asyncio.gather(first, second)
|
||||
|
||||
assert max_concurrent == 1
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_stop_cancels_active_task(self):
|
||||
from nanobot.bus.events import InboundMessage
|
||||
|
||||
Reference in New Issue
Block a user