Queue background errors

This commit is contained in:
thePR0M3TH3AN
2025-08-05 23:26:54 -04:00
parent b49e37b6e1
commit f0a7fb7da1
3 changed files with 75 additions and 0 deletions

View File

@@ -1064,6 +1064,7 @@ def display_menu(
getattr(password_manager, "start_background_relay_check", lambda: None)()
_display_live_stats(password_manager)
while True:
getattr(password_manager, "poll_background_errors", lambda: None)()
fp, parent_fp, child_fp = getattr(
password_manager,
"header_fingerprint_args",

View File

@@ -177,6 +177,7 @@ class PasswordManager:
self.state_manager: Optional[StateManager] = None
self.stats_manager: StatsManager = StatsManager()
self.notifications: queue.Queue[Notification] = queue.Queue()
self.error_queue: queue.Queue[Exception] = queue.Queue()
self._current_notification: Optional[Notification] = None
self._notification_expiry: float = 0.0
@@ -307,6 +308,18 @@ class PasswordManager:
return self._current_notification
return None
def poll_background_errors(self) -> None:
"""Process exceptions raised by background threads."""
if not hasattr(self, "error_queue"):
return
while True:
try:
exc = self.error_queue.get_nowait()
except queue.Empty:
break
logger.warning("Background task failed: %s", exc)
self.notify(f"Background task failed: {exc}", level="WARNING")
def lock_vault(self) -> None:
"""Clear sensitive information from memory."""
if self.entry_manager is not None:
@@ -1430,6 +1443,8 @@ class PasswordManager:
await self.sync_index_from_nostr_async()
except Exception as exc:
logger.warning(f"Background sync failed: {exc}")
if hasattr(self, "error_queue"):
self.error_queue.put(exc)
try:
loop = asyncio.get_running_loop()
@@ -1473,6 +1488,8 @@ class PasswordManager:
)
except Exception as exc:
logger.warning(f"Relay health check failed: {exc}")
if hasattr(self, "error_queue"):
self.error_queue.put(exc)
self._relay_thread = threading.Thread(target=_worker, daemon=True)
self._relay_thread.start()
@@ -1489,6 +1506,8 @@ class PasswordManager:
bus.publish("sync_finished", result)
except Exception as exc:
logging.error(f"Background vault sync failed: {exc}", exc_info=True)
if hasattr(self, "error_queue"):
self.error_queue.put(exc)
try:
loop = asyncio.get_running_loop()

View File

@@ -0,0 +1,55 @@
import logging
import queue
import seedpass.core.manager as manager_module
def _make_pm():
pm = manager_module.PasswordManager.__new__(manager_module.PasswordManager)
pm.offline_mode = False
pm.notifications = queue.Queue()
pm.error_queue = queue.Queue()
pm.notify = lambda msg, level="INFO": pm.notifications.put(
manager_module.Notification(msg, level)
)
return pm
def test_start_background_sync_error(monkeypatch, caplog):
pm = _make_pm()
async def failing_sync(*_args, **_kwargs):
raise RuntimeError("boom")
monkeypatch.setattr(pm, "attempt_initial_sync_async", failing_sync)
monkeypatch.setattr(pm, "sync_index_from_nostr_async", failing_sync)
pm.start_background_sync()
pm._sync_task.join(timeout=1)
with caplog.at_level(logging.WARNING):
pm.poll_background_errors()
note = pm.notifications.get_nowait()
assert "boom" in note.message
assert "boom" in caplog.text
def test_start_background_relay_check_error(monkeypatch, caplog):
pm = _make_pm()
class DummyClient:
def check_relay_health(self, *_args, **_kwargs):
raise RuntimeError("relay boom")
pm.nostr_client = DummyClient()
pm.start_background_relay_check()
pm._relay_thread.join(timeout=1)
with caplog.at_level(logging.WARNING):
pm.poll_background_errors()
note = pm.notifications.get_nowait()
assert "relay boom" in note.message
assert "relay boom" in caplog.text