Browse Source

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
timeout in this case, freezing the GUI for 30 seconds (when switching away).
patch-4
SomberNight 4 years ago
parent
commit
e83f0dd3fc
No known key found for this signature in database GPG Key ID: B33B5F232C6271E9
  1. 6
      electrum/interface.py
  2. 10
      electrum/network.py

6
electrum/interface.py

@ -616,7 +616,8 @@ class Interface(Logger):
return conn, res['count'] return conn, res['count']
def is_main_server(self) -> bool: 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): async def open_session(self, sslc, exit_early=False):
session_factory = lambda *args, iface=self, **kwargs: NotificationSession(*args, **kwargs, interface=iface) session_factory = lambda *args, iface=self, **kwargs: NotificationSession(*args, **kwargs, interface=iface)
@ -678,6 +679,9 @@ class Interface(Logger):
await asyncio.sleep(60) await asyncio.sleep(60)
async def close(self): 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: if self.session:
await self.session.close() await self.session.close()
# monitor_connection will cancel tasks # monitor_connection will cancel tasks

10
electrum/network.py

@ -682,7 +682,8 @@ class Network(Logger, NetworkRetryManager[ServerAddr]):
# However, for headers sub, give preference to this interface # However, for headers sub, give preference to this interface
# over unknown ones, i.e. start it again right away. # over unknown ones, i.e. start it again right away.
if old_server and old_server != server: 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: if len(self.interfaces) <= self.num_server:
await self.taskgroup.spawn(self._run_new_interface(old_server)) await self.taskgroup.spawn(self._run_new_interface(old_server))
@ -711,8 +712,9 @@ class Network(Logger, NetworkRetryManager[ServerAddr]):
with self.interfaces_lock: with self.interfaces_lock:
if self.interfaces.get(interface.server) == interface: if self.interfaces.get(interface.server) == interface:
self.interfaces.pop(interface.server) self.interfaces.pop(interface.server)
if interface.server == self.default_server: if interface == self.interface:
self.interface = None self.interface = None
# this can take some time if server/connection is slow:
await interface.close() await interface.close()
@with_recent_servers_lock @with_recent_servers_lock
@ -729,8 +731,8 @@ class Network(Logger, NetworkRetryManager[ServerAddr]):
'''A connection to server either went down, or was never made. '''A connection to server either went down, or was never made.
We distinguish by whether it is in self.interfaces.''' We distinguish by whether it is in self.interfaces.'''
if not interface: return if not interface: return
server = interface.server # note: don't rely on interface.server for comparisons here
if server == self.default_server: if interface == self.interface:
self._set_status('disconnected') self._set_status('disconnected')
await self._close_interface(interface) await self._close_interface(interface)
util.trigger_callback('network_updated') util.trigger_callback('network_updated')

Loading…
Cancel
Save