From e0246b30b9e4c5702f6fd48b4139e0a51d745af7 Mon Sep 17 00:00:00 2001 From: SomberNight Date: Fri, 5 Nov 2021 18:33:03 +0100 Subject: [PATCH] daemon: if taskgroup dies, show error in GUI If daemon.taskgroup dies - in GUI mode, show a crash reporter window to the user, instead of immediately stopping the whole process. - in daemon mode, log exception and stop process, as before. --- electrum/daemon.py | 20 ++++++++++++++------ electrum/gui/qt/__init__.py | 2 ++ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/electrum/daemon.py b/electrum/daemon.py index 211d197b6..9a7002e5f 100644 --- a/electrum/daemon.py +++ b/electrum/daemon.py @@ -487,7 +487,10 @@ class Daemon(Logger): if self.config.get('use_gossip', False): self.network.start_gossip() - self._stopping_soon = threading.Event() + self.exception = None # type: Optional[Exception] + + self._stop_entered = False + self._stopping_soon_or_errored = threading.Event() self._stopped_event = threading.Event() self.taskgroup = TaskGroup() asyncio.run_coroutine_threadsafe(self._run(jobs=daemon_jobs), self.asyncio_loop) @@ -505,9 +508,13 @@ class Daemon(Logger): raise except Exception as e: self.logger.exception("taskgroup died.") + self.exception = e + util.send_exception_to_crash_reporter(e) finally: self.logger.info("taskgroup stopped.") - await self.stop() + # note: we could just "await self.stop()", but in that case GUI users would + # not see the exception (especially if the GUI did not start yet). + self._stopping_soon_or_errored.set() def load_wallet(self, path, password, *, manual_upgrades=True) -> Optional[Abstract_Wallet]: path = standardize_path(path) @@ -571,15 +578,16 @@ class Daemon(Logger): def run_daemon(self): try: - self._stopping_soon.wait() + self._stopping_soon_or_errored.wait() except KeyboardInterrupt: asyncio.run_coroutine_threadsafe(self.stop(), self.asyncio_loop).result() self._stopped_event.wait() async def stop(self): - if self._stopping_soon.is_set(): + if self._stop_entered: return - self._stopping_soon.set() + self._stop_entered = True + self._stopping_soon_or_errored.set() self.logger.info("stop() entered. initiating shutdown") try: if self.gui_object: @@ -610,7 +618,7 @@ class Daemon(Logger): try: gui = __import__('electrum.gui.' + gui_name, fromlist=['electrum']) self.gui_object = gui.ElectrumGui(config, self, plugins) - if not self._stopping_soon.is_set(): + if not self._stop_entered: self.gui_object.main() else: # If daemon.stop() was called before gui_object got created, stop gui now. diff --git a/electrum/gui/qt/__init__.py b/electrum/gui/qt/__init__.py index 80b53187e..3528bc6f5 100644 --- a/electrum/gui/qt/__init__.py +++ b/electrum/gui/qt/__init__.py @@ -403,6 +403,8 @@ class ElectrumGui(Logger): signal.signal(signal.SIGINT, lambda *args: self.app.quit()) # hook for crash reporter Exception_Hook.maybe_setup(config=self.config) + if self.daemon.exception: # if daemon errored too early, replay that now: + send_exception_to_crash_reporter(self.daemon.exception) # first-start network-setup try: self.init_network()