Răsfoiți Sursa

Fix finalizer warnings in ControlClient

Alexander Borzunov 4 ani în urmă
părinte
comite
5a84ba76c5

+ 3 - 0
hivemind/p2p/p2p_daemon.py

@@ -66,6 +66,7 @@ class P2P:
 
 
     def __init__(self):
     def __init__(self):
         self.peer_id = None
         self.peer_id = None
+        self._client = None
         self._child = None
         self._child = None
         self._alive = False
         self._alive = False
         self._reader_task = None
         self._reader_task = None
@@ -500,6 +501,8 @@ class P2P:
             await self._child.wait()
             await self._child.wait()
 
 
     def _terminate(self) -> None:
     def _terminate(self) -> None:
+        if self._client is not None:
+            self._client.close()
         if self._listen_task is not None:
         if self._listen_task is not None:
             self._listen_task.cancel()
             self._listen_task.cancel()
         if self._reader_task is not None:
         if self._reader_task is not None:

+ 13 - 15
hivemind/p2p/p2p_daemon_bindings/control.py

@@ -5,7 +5,7 @@ Author: Kevin Mai-Husan Chia
 """
 """
 
 
 import asyncio
 import asyncio
-from contextlib import asynccontextmanager, closing
+from contextlib import asynccontextmanager, closing, suppress
 from typing import AsyncIterator, Awaitable, Callable, Dict, Iterable, Optional, Sequence, Tuple
 from typing import AsyncIterator, Awaitable, Callable, Dict, Iterable, Optional, Sequence, Tuple
 from uuid import UUID, uuid4
 from uuid import UUID, uuid4
 
 
@@ -109,6 +109,15 @@ class ControlClient:
 
 
         return control
         return control
 
 
+    def close(self) -> None:
+        if self._read_task is not None:
+            self._read_task.cancel()
+        if self._write_task is not None:
+            self._write_task.cancel()
+
+    def __del__(self):
+        self.close()
+
     async def _handler(self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter):
     async def _handler(self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter):
         pb_stream_info = p2pd_pb.StreamInfo()  # type: ignore
         pb_stream_info = p2pd_pb.StreamInfo()  # type: ignore
         await read_pbmsg_safe(reader, pb_stream_info)
         await read_pbmsg_safe(reader, pb_stream_info)
@@ -134,14 +143,8 @@ class ControlClient:
         else:
         else:
             raise ValueError(f"Protocol not supported: {protocols.protocol_with_code(proto_code)}")
             raise ValueError(f"Protocol not supported: {protocols.protocol_with_code(proto_code)}")
 
 
-        try:
-            async with server:
-                yield self
-        finally:
-            if self._read_task is not None:
-                self._read_task.cancel()
-            if self._write_task is not None:
-                self._write_task.cancel()
+        async with server:
+            yield self
 
 
     async def _read_from_persistent_conn(self, reader: asyncio.StreamReader):
     async def _read_from_persistent_conn(self, reader: asyncio.StreamReader):
         while True:
         while True:
@@ -172,12 +175,7 @@ class ControlClient:
     async def _write_to_persistent_conn(self, writer: asyncio.StreamWriter):
     async def _write_to_persistent_conn(self, writer: asyncio.StreamWriter):
         with closing(writer):
         with closing(writer):
             while True:
             while True:
-                try:
-                    msg = await self._pending_messages.get()
-                except ValueError:
-                    # Ignore "ValueError: I/O operation on closed file" because it is normal behavior
-                    # if the connection is closed by the other party
-                    break
+                msg = await self._pending_messages.get()
                 await write_pbmsg(writer, msg)
                 await write_pbmsg(writer, msg)
 
 
     async def _handle_persistent_request(self, call_id: UUID, request: p2pd_pb.CallUnaryRequest):
     async def _handle_persistent_request(self, call_id: UUID, request: p2pd_pb.CallUnaryRequest):

+ 6 - 0
hivemind/p2p/p2p_daemon_bindings/p2pclient.py

@@ -29,6 +29,12 @@ class Client:
 
 
         return client
         return client
 
 
+    def close(self) -> None:
+        self.control.close()
+
+    def __del__(self):
+        self.close()
+
     @asynccontextmanager
     @asynccontextmanager
     async def listen(self) -> AsyncIterator["Client"]:
     async def listen(self) -> AsyncIterator["Client"]:
         """
         """