tnetwork: when switching servers, don't wait for old interface to close - electrum - Electrum Bitcoin wallet HTML git clone https://git.parazyd.org/electrum DIR Log DIR Files DIR Refs DIR Submodules --- DIR commit e83f0dd3fc4e19c8845fc21f344400f1b0a7eebf DIR parent 91cdd12fa274e29d45a8684d7faf2942b23dfbd9 HTML Author: SomberNight <somber.night@protonmail.com> Date: Sun, 13 Dec 2020 18:08:36 +0100 network: when switching servers, don't wait for old interface to close The GUI blocks until network.set_parameters returns when switching servers, which waits for switch_to_interface, which used to wait until interface.close() returns. interface.close() tries to flush buffered writes to the wire, with a 30 sec timeout. If the server or the network connection is slow, flushing the buffer can take several seconds. In particular, servers running Fulcrum always seem to ttimeout in this case, freezing the GUI for 30 seconds (when switching away). Diffstat: M electrum/interface.py | 6 +++++- M electrum/network.py | 10 ++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) --- DIR diff --git a/electrum/interface.py b/electrum/interface.py t@@ -616,7 +616,8 @@ class Interface(Logger): return conn, res['count'] def is_main_server(self) -> bool: - return self.network.default_server == self.server + return (self.network.interface == self or + self.network.interface is None and self.network.default_server == self.server) async def open_session(self, sslc, exit_early=False): session_factory = lambda *args, iface=self, **kwargs: NotificationSession(*args, **kwargs, interface=iface) t@@ -678,6 +679,9 @@ class Interface(Logger): await asyncio.sleep(60) async def close(self): + """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 self.session: await self.session.close() # monitor_connection will cancel tasks DIR diff --git a/electrum/network.py b/electrum/network.py t@@ -682,7 +682,8 @@ class Network(Logger, NetworkRetryManager[ServerAddr]): # However, for headers sub, give preference to this interface # over unknown ones, i.e. start it again right away. if old_server and old_server != server: - await self._close_interface(old_interface) + # don't wait for old_interface to close as that might be slow: + await self.taskgroup.spawn(self._close_interface(old_interface)) if len(self.interfaces) <= self.num_server: await self.taskgroup.spawn(self._run_new_interface(old_server)) t@@ -711,8 +712,9 @@ class Network(Logger, NetworkRetryManager[ServerAddr]): with self.interfaces_lock: if self.interfaces.get(interface.server) == interface: self.interfaces.pop(interface.server) - if interface.server == self.default_server: + if interface == self.interface: self.interface = None + # this can take some time if server/connection is slow: await interface.close() @with_recent_servers_lock t@@ -729,8 +731,8 @@ class Network(Logger, NetworkRetryManager[ServerAddr]): '''A connection to server either went down, or was never made. We distinguish by whether it is in self.interfaces.''' if not interface: return - server = interface.server - if server == self.default_server: + # note: don't rely on interface.server for comparisons here + if interface == self.interface: self._set_status('disconnected') await self._close_interface(interface) util.trigger_callback('network_updated')