refac
This commit is contained in:
@@ -1923,8 +1923,6 @@ async def chat_completion(
|
|||||||
# uses anyio task groups whose cancel scopes enforce
|
# uses anyio task groups whose cancel scopes enforce
|
||||||
# same-task exit. Do NOT wrap in asyncio.shield() or
|
# same-task exit. Do NOT wrap in asyncio.shield() or
|
||||||
# asyncio.wait_for() — both create a new task.
|
# asyncio.wait_for() — both create a new task.
|
||||||
# MCPClient.disconnect() self-shields via
|
|
||||||
# anyio.CancelScope(shield=True).
|
|
||||||
try:
|
try:
|
||||||
if mcp_clients := metadata.get('mcp_clients'):
|
if mcp_clients := metadata.get('mcp_clients'):
|
||||||
for client in reversed(list(mcp_clients.values())):
|
for client in reversed(list(mcp_clients.values())):
|
||||||
@@ -1932,14 +1930,29 @@ async def chat_completion(
|
|||||||
await client.disconnect()
|
await client.disconnect()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.debug(f'Error disconnecting MCP client: {e}')
|
log.debug(f'Error disconnecting MCP client: {e}')
|
||||||
|
except asyncio.CancelledError:
|
||||||
|
# Let the client close asynchronously by GC
|
||||||
|
pass
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.debug(f'Error cleaning up MCP clients: {e}')
|
log.debug(f'Error cleaning up MCP clients: {e}')
|
||||||
|
except asyncio.CancelledError:
|
||||||
|
pass
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if metadata.get('chat_id'):
|
if metadata.get('chat_id'):
|
||||||
event_emitter = await get_event_emitter(metadata, update_db=False)
|
async def emit_inactive_event():
|
||||||
if event_emitter:
|
try:
|
||||||
await event_emitter({'type': 'chat:active', 'data': {'active': False}})
|
event_emitter = await get_event_emitter(metadata, update_db=False)
|
||||||
|
if event_emitter:
|
||||||
|
await event_emitter({'type': 'chat:active', 'data': {'active': False}})
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Shield the event emission so it finishes even if the main task is cancelled
|
||||||
|
await asyncio.shield(emit_inactive_event())
|
||||||
|
except asyncio.CancelledError:
|
||||||
|
pass
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -156,14 +156,14 @@ class MCPClient:
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
# IMPORTANT: Do NOT use asyncio.shield() or asyncio.wait_for()
|
# IMPORTANT: Do NOT use asyncio.shield() or asyncio.wait_for()
|
||||||
# here — both create a new asyncio task. The MCP SDK's
|
# because they create a new asyncio task, which violates the MCP SDK's
|
||||||
# streamablehttp_client uses anyio task groups / cancel scopes
|
# requirement that its TaskGroup be exited in the exact same task.
|
||||||
# that MUST be exited in the same task they were entered in.
|
# ALSO do NOT use anyio.CancelScope(shield=True) or anyio.fail_after(),
|
||||||
# Using anyio.CancelScope(shield=True) protects from
|
# because they push a new cancel scope onto the task, violating LIFO
|
||||||
# CancelledError while staying in the current task.
|
# order when aclose() attempts to exit the inner TaskGroup.
|
||||||
with anyio.CancelScope(shield=True):
|
# We simply call aclose() directly. If the task is cancelled, the
|
||||||
with anyio.fail_after(5.0):
|
# sockets will eventually be cleaned up by garbage collection.
|
||||||
await exit_stack.aclose()
|
await exit_stack.aclose()
|
||||||
except TimeoutError:
|
except TimeoutError:
|
||||||
log.warning('MCPClient.disconnect() timed out after 5 s')
|
log.warning('MCPClient.disconnect() timed out after 5 s')
|
||||||
except RuntimeError as exc:
|
except RuntimeError as exc:
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ aiocache
|
|||||||
aiofiles
|
aiofiles
|
||||||
starlette-compress==1.7.0
|
starlette-compress==1.7.0
|
||||||
Brotli==1.2.0
|
Brotli==1.2.0
|
||||||
|
brotlicffi==1.2.0.1
|
||||||
httpx[socks,http2,zstd,cli,brotli]==0.28.1
|
httpx[socks,http2,zstd,cli,brotli]==0.28.1
|
||||||
starsessions[redis]==2.2.1
|
starsessions[redis]==2.2.1
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user