mirror of
https://github.com/agessaman/meshcore-bot.git
synced 2026-08-28 05:14:12 +00:00
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:
+6
-21
@@ -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
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user