Refactor cleanup methods in core.py and mesh_graph.py to suppress logging during shutdown

- Updated the _cleanup_web_viewer and _cleanup_mesh_graph methods to avoid logging errors during shutdown, as the logger's stream may be closed at that time.
- Modified the shutdown method in MeshGraph to prevent logging of flushing errors, enhancing stability during the atexit process.
- Adjusted test configurations to use Path objects for bot_root and local_root, improving path handling in tests.
This commit is contained in:
agessaman
2026-03-11 20:41:44 -07:00
parent 6ee4639ab7
commit 2178a80dca
5 changed files with 17 additions and 32 deletions
+6 -21
View File
@@ -1498,42 +1498,27 @@ long_jokes = false
def _cleanup_web_viewer(self) -> None:
"""Cleanup web viewer resources on exit.
Called by atexit handler to ensure the web viewer process is terminated
properly when the bot shuts down.
"""
try:
if hasattr(self, 'web_viewer_integration') and self.web_viewer_integration:
# Web viewer has simpler cleanup
self.web_viewer_integration.stop_viewer()
try:
self.logger.info("Web viewer cleanup completed")
except (AttributeError, TypeError):
print("Web viewer cleanup completed")
except (OSError, AttributeError, TypeError) as e:
try:
self.logger.error(f"Error during web viewer cleanup: {e}")
except (AttributeError, TypeError):
print(f"Error during web viewer cleanup: {e}")
except (OSError, AttributeError, TypeError, ValueError, IOError):
pass # Do not log; stream may be closed during atexit
def _cleanup_mesh_graph(self) -> None:
"""Cleanup mesh graph resources on exit.
Called by atexit handler to ensure graph state is persisted
properly when the bot shuts down.
"""
try:
if hasattr(self, 'mesh_graph') and self.mesh_graph:
self.mesh_graph.shutdown()
try:
self.logger.info("Mesh graph cleanup completed")
except (AttributeError, TypeError):
print("Mesh graph cleanup completed")
except (OSError, AttributeError, TypeError) as e:
try:
self.logger.error(f"Error during mesh graph cleanup: {e}")
except (AttributeError, TypeError):
print(f"Error during mesh graph cleanup: {e}")
except (OSError, AttributeError, TypeError, ValueError, IOError):
pass # Do not log; stream may be closed during atexit
async def send_startup_advert(self) -> None:
"""Send a startup advertisement if configured.
+4 -10
View File
@@ -1393,18 +1393,12 @@ class MeshGraph:
def shutdown(self):
"""Shutdown graph, flushing all pending writes."""
self.logger.info("Shutting down mesh graph, flushing pending writes...")
# Do not log here: atexit may run after the logger's stream is closed.
# Signal shutdown
self._shutdown_event.set()
# Flush pending updates
try:
self._flush_pending_updates_sync()
except Exception as e:
self.logger.warning(f"Error flushing graph updates on shutdown: {e}")
# Log final statistics
if self.edges:
total_observations = sum(e['observation_count'] for e in self.edges.values())
self.logger.info(f"Graph shutdown complete: {len(self.edges)} edges, {total_observations} total observations")
except Exception:
pass # Avoid logging; stream may be closed during atexit
+3 -1
View File
@@ -7,6 +7,7 @@ import pytest
import sqlite3
import configparser
from contextlib import closing
from pathlib import Path
from unittest.mock import Mock, MagicMock, AsyncMock
from datetime import datetime, timedelta
from typing import Any, Optional
@@ -236,7 +237,8 @@ def mock_bot(mock_logger, test_config, test_db):
bot.logger = mock_logger
bot.config = test_config
bot.db_manager = test_db
bot.bot_root = '/tmp' # Dummy path for testing
bot.bot_root = Path("/tmp") # Path for CommandManager local_commands_dir
bot._local_root = None # Use bot_root / local / commands in CommandManager
bot.prefix_hex_chars = 2 # For path/prefix logic (PR #77)
bot.key_prefix = lambda pk: (pk or '')[: getattr(bot, 'prefix_hex_chars', 2)] # For path_command graph selection
+1
View File
@@ -18,6 +18,7 @@ def cm_bot(mock_logger):
bot = Mock()
bot.logger = mock_logger
bot.bot_root = Path("/tmp")
bot._local_root = None # Use bot_root / local / commands in CommandManager
bot.config = ConfigParser()
bot.config.add_section("Bot")
bot.config.set("Bot", "bot_name", "TestBot")
+3
View File
@@ -5,6 +5,7 @@ Tests that all commands properly handle command prefixes when enabled
"""
import pytest
from pathlib import Path
from unittest.mock import Mock, MagicMock, patch
from configparser import ConfigParser
@@ -49,6 +50,8 @@ def mock_bot():
bot.bot_tx_rate_limiter = Mock()
bot.bot_tx_rate_limiter.wait_for_tx = Mock()
bot.tx_delay_ms = 0
bot.bot_root = Path("/tmp")
bot._local_root = None # CommandManager uses bot_root / local / commands
return bot