From 8db2489739be2e3347e4beaa69a8701ffa0a8283 Mon Sep 17 00:00:00 2001 From: SomberNight Date: Mon, 21 Oct 2024 18:28:32 +0000 Subject: [PATCH] qt gui: faster clean-up of hung UpdateCheckThread during exit If you closed a main_window soon after opening it, and the UpdateCheckThread network request was slow and still in progress, the gui would freeze until the network request finished. --- electrum/gui/qt/main_window.py | 3 +-- electrum/gui/qt/update_checker.py | 11 ++++++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/electrum/gui/qt/main_window.py b/electrum/gui/qt/main_window.py index 5d2bb5e0f..099a82733 100644 --- a/electrum/gui/qt/main_window.py +++ b/electrum/gui/qt/main_window.py @@ -2525,8 +2525,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger, QtEventListener): self.close_wallet() if self._update_check_thread: - self._update_check_thread.exit() - self._update_check_thread.wait() + self._update_check_thread.stop() if self.tray: self.tray = None self.gui_object.timer.timeout.disconnect(self.timer_actions) diff --git a/electrum/gui/qt/update_checker.py b/electrum/gui/qt/update_checker.py index 1baaa00af..7112f61d1 100644 --- a/electrum/gui/qt/update_checker.py +++ b/electrum/gui/qt/update_checker.py @@ -4,6 +4,7 @@ import asyncio import base64 +from typing import Optional from PyQt6.QtCore import Qt, QThread, pyqtSignal from PyQt6.QtWidgets import (QWidget, QVBoxLayout, QLabel, QProgressBar, @@ -102,6 +103,7 @@ class UpdateCheckThread(QThread, Logger): QThread.__init__(self) Logger.__init__(self) self.network = Network.get_instance() + self._fut = None # type: Optional[asyncio.Future] async def get_update_info(self): # note: Use long timeout here as it is not critical that we get a response fast, @@ -137,10 +139,17 @@ class UpdateCheckThread(QThread, Logger): if not self.network: self.failed.emit() return + self._fut = asyncio.run_coroutine_threadsafe(self.get_update_info(), self.network.asyncio_loop) try: - update_info = asyncio.run_coroutine_threadsafe(self.get_update_info(), self.network.asyncio_loop).result() + update_info = self._fut.result() except Exception as e: self.logger.info(f"got exception: '{repr(e)}'") self.failed.emit() else: self.checked.emit(update_info) + + def stop(self): + if self._fut: + self._fut.cancel() + self.exit() + self.wait()