diff --git a/electrum/interface.py b/electrum/interface.py index 291f69e69..8181e555f 100644 --- a/electrum/interface.py +++ b/electrum/interface.py @@ -686,12 +686,17 @@ class Interface(Logger): self.network.update_fee_estimates() await asyncio.sleep(60) - async def close(self): + async def close(self, *, force_after: int = None): """Closes the connection and waits for it to be closed. We try to flush buffered data to the wire, so this can take some time. """ + if force_after is None: + # We give up after a while and just abort the connection. + # Note: specifically if the server is running Fulcrum, waiting seems hopeless, + # the connection must be aborted (see https://github.com/cculianu/Fulcrum/issues/76) + force_after = 2 # seconds if self.session: - await self.session.close() + await self.session.close(force_after=force_after) # monitor_connection will cancel tasks async def run_fetch_blocks(self): diff --git a/electrum/network.py b/electrum/network.py index 682f8db26..22c13c5f9 100644 --- a/electrum/network.py +++ b/electrum/network.py @@ -1220,7 +1220,8 @@ class Network(Logger, NetworkRetryManager[ServerAddr]): async def _stop(self, full_shutdown=False): self.logger.info("stopping network") try: - await asyncio.wait_for(self.taskgroup.cancel_remaining(), timeout=2) + # note: cancel_remaining ~cannot be cancelled, it suppresses CancelledError + await asyncio.wait_for(self.taskgroup.cancel_remaining(log=True), timeout=2) except (asyncio.TimeoutError, asyncio.CancelledError) as e: self.logger.info(f"exc during main_taskgroup cancellation: {repr(e)}") self.taskgroup = None