@@ -22,13 +22,14 @@ class ConnectionManager(Generic[T], ABC):
22
22
used with MCP connectors.
23
23
"""
24
24
25
- def __init__ (self ):
25
+ def __init__ (self ) -> None :
26
26
"""Initialize a new connection manager."""
27
27
self ._ready_event = asyncio .Event ()
28
28
self ._done_event = asyncio .Event ()
29
+ self ._stop_event = asyncio .Event ()
29
30
self ._exception : Exception | None = None
30
31
self ._connection : T | None = None
31
- self ._task : asyncio .Task | None = None
32
+ self ._task : asyncio .Task [ None ] | None = None
32
33
33
34
@abstractmethod
34
35
async def _establish_connection (self ) -> T :
@@ -86,20 +87,15 @@ async def start(self) -> T:
86
87
87
88
async def stop (self ) -> None :
88
89
"""Stop the connection manager and close the connection."""
90
+ # Signal stop to the connection task instead of cancelling it, avoids
91
+ # propagating CancelledError to unrelated tasks.
89
92
if self ._task and not self ._task .done ():
90
- # Cancel the task
91
- logger .debug (f"Cancelling { self .__class__ .__name__ } task" )
92
- self ._task .cancel ()
93
-
94
- # Wait for it to complete
95
- try :
96
- await self ._task
97
- except asyncio .CancelledError :
98
- logger .debug (f"{ self .__class__ .__name__ } task cancelled successfully" )
99
- except Exception as e :
100
- logger .warning (f"Error stopping { self .__class__ .__name__ } task: { e } " )
101
-
102
- # Wait for the connection to be done
93
+ logger .debug (f"Signaling stop to { self .__class__ .__name__ } task" )
94
+ self ._stop_event .set ()
95
+ # Wait for it to finish gracefully
96
+ await self ._task
97
+
98
+ # Ensure cleanup completed
103
99
await self ._done_event .wait ()
104
100
logger .debug (f"{ self .__class__ .__name__ } task completed" )
105
101
@@ -125,14 +121,8 @@ async def _connection_task(self) -> None:
125
121
# Signal that the connection is ready
126
122
self ._ready_event .set ()
127
123
128
- # Wait indefinitely until cancelled
129
- try :
130
- # This keeps the connection open until cancelled
131
- await asyncio .Event ().wait ()
132
- except asyncio .CancelledError :
133
- # Expected when stopping
134
- logger .debug (f"{ self .__class__ .__name__ } task received cancellation" )
135
- pass
124
+ # Wait until stop is requested
125
+ await self ._stop_event .wait ()
136
126
137
127
except Exception as e :
138
128
# Store the exception
0 commit comments