URI: 
       tnetwork: don't let _maintain_sessions die from CancelledError - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 62e352a2a8e61ae930b6a09b1457d5419afea35c
   DIR parent b3ff173b4507e8325c65d607a4547320ba2c8798
  HTML Author: SomberNight <somber.night@protonmail.com>
       Date:   Sun,  9 Dec 2018 20:04:42 +0100
       
       network: don't let _maintain_sessions die from CancelledError
       
       as then the network would get paralysed and no one can fix it
       
       Diffstat:
         M electrum/network.py                 |      29 +++++++++++++++++++----------
       
       1 file changed, 19 insertions(+), 10 deletions(-)
       ---
   DIR diff --git a/electrum/network.py b/electrum/network.py
       t@@ -197,7 +197,7 @@ class Network(PrintError):
                if not self.default_server:
                    self.default_server = pick_random_server()
        
       -        self.main_taskgroup = None
       +        self.main_taskgroup = None  # type: TaskGroup
        
                # locks
                self.restart_lock = asyncio.Lock()
       t@@ -817,7 +817,7 @@ class Network(PrintError):
        
            async def _start(self):
                assert not self.main_taskgroup
       -        self.main_taskgroup = SilentTaskGroup()
       +        self.main_taskgroup = main_taskgroup = SilentTaskGroup()
                assert not self.interface and not self.interfaces
                assert not self.connecting and not self.server_queue
                self.print_error('starting network')
       t@@ -831,7 +831,9 @@ class Network(PrintError):
                async def main():
                    try:
                        await self._init_headers_file()
       -                async with self.main_taskgroup as group:
       +                # note: if a task finishes with CancelledError, that
       +                # will NOT raise, and the group will keep the other tasks running
       +                async with main_taskgroup as group:
                            await group.spawn(self._maintain_sessions())
                            [await group.spawn(job) for job in self._jobs]
                    except Exception as e:
       t@@ -852,7 +854,7 @@ class Network(PrintError):
                    await asyncio.wait_for(self.main_taskgroup.cancel_remaining(), timeout=2)
                except (asyncio.TimeoutError, asyncio.CancelledError) as e:
                    self.print_error(f"exc during main_taskgroup cancellation: {repr(e)}")
       -        self.main_taskgroup = None
       +        self.main_taskgroup = None  # type: TaskGroup
                self.interface = None  # type: Interface
                self.interfaces = {}  # type: Dict[str, Interface]
                self.connecting.clear()
       t@@ -884,13 +886,11 @@ class Network(PrintError):
                        await self.switch_to_interface(self.default_server)
        
            async def _maintain_sessions(self):
       -        while True:
       -            # launch already queued up new interfaces
       +        async def launch_already_queued_up_new_interfaces():
                    while self.server_queue.qsize() > 0:
                        server = self.server_queue.get()
                        await self.main_taskgroup.spawn(self._run_new_interface(server))
       -
       -            # maybe queue new interfaces to be launched later
       +        async def maybe_queue_new_interfaces_to_be_launched_later():
                    now = time.time()
                    for i in range(self.num_server - len(self.interfaces) - len(self.connecting)):
                        self._start_random_interface()
       t@@ -898,13 +898,22 @@ class Network(PrintError):
                        self.print_error('network: retrying connections')
                        self.disconnected_servers = set([])
                        self.nodes_retry_time = now
       -
       -            # main interface
       +        async def maintain_main_interface():
                    await self._ensure_there_is_a_main_interface()
                    if self.is_connected():
                        if self.config.is_fee_estimates_update_required():
                            await self.interface.group.spawn(self._request_fee_estimates, self.interface)
        
       +        while True:
       +            try:
       +                await launch_already_queued_up_new_interfaces()
       +                await maybe_queue_new_interfaces_to_be_launched_later()
       +                await maintain_main_interface()
       +            except asyncio.CancelledError:
       +                # suppress spurious cancellations
       +                group = self.main_taskgroup
       +                if not group or group._closed:
       +                    raise
                    await asyncio.sleep(0.1)