mirror of
https://github.com/agessaman/meshcore-bot.git
synced 2026-11-03 19:42:22 +00:00
_start_cleanup_scheduler and _cleanup_old_data move verbatim to modules/web_viewer/cleanup.py (AST-identical; the other 23 BotDataViewer methods are unchanged). app.py keeps importing delete_timestamp_rows_in_chunks and retention_delete_settings so modules.web_viewer.app still exposes them; as with the earlier mixins, patching those names on app no longer reaches the moved code. app.py is 4,808 lines.
83 lines
3.1 KiB
Python
83 lines
3.1 KiB
Python
"""Background cleanup for the web viewer: the hourly scheduler that drops
|
|
stale Socket.IO clients and prunes old packet_stream rows."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import time
|
|
from contextlib import suppress
|
|
from typing import Any
|
|
|
|
from modules.db_retention import (
|
|
delete_timestamp_rows_in_chunks,
|
|
retention_delete_settings,
|
|
)
|
|
|
|
|
|
class CleanupSchedulerMixin:
|
|
"""Mixed into BotDataViewer."""
|
|
|
|
_cleanup_stale_clients: Any
|
|
_with_db_connection: Any
|
|
config: Any
|
|
logger: Any
|
|
|
|
def _start_cleanup_scheduler(self):
|
|
"""Start background thread for periodic database cleanup"""
|
|
import threading
|
|
|
|
def cleanup_scheduler():
|
|
import time
|
|
while True:
|
|
try:
|
|
# Clean up stale clients every 5 minutes
|
|
for _ in range(12): # 12 x 5 minutes = 1 hour
|
|
time.sleep(300) # 5 minutes
|
|
self._cleanup_stale_clients()
|
|
|
|
# Clean up old data every hour (after 12 stale client cleanups)
|
|
self._cleanup_old_data()
|
|
|
|
except Exception as e:
|
|
self.logger.error(f"Error in cleanup scheduler: {e}", exc_info=True)
|
|
time.sleep(60) # Sleep on error
|
|
|
|
# Start the cleanup thread
|
|
cleanup_thread = threading.Thread(target=cleanup_scheduler, daemon=True)
|
|
cleanup_thread.start()
|
|
self.logger.info("Cleanup scheduler started")
|
|
|
|
def _cleanup_old_data(self, days_to_keep: int | None = None):
|
|
"""Clean up old packet stream data to prevent database bloat.
|
|
Uses [Data_Retention] packet_stream_retention_days when days_to_keep is not provided."""
|
|
try:
|
|
import sqlite3
|
|
|
|
if days_to_keep is None:
|
|
days_to_keep = 3
|
|
if self.config.has_section('Data_Retention') and self.config.has_option('Data_Retention', 'packet_stream_retention_days'):
|
|
with suppress(ValueError, TypeError):
|
|
days_to_keep = self.config.getint('Data_Retention', 'packet_stream_retention_days')
|
|
|
|
cutoff_time = time.time() - (days_to_keep * 24 * 60 * 60)
|
|
batch_size, pause_seconds = retention_delete_settings(self.config)
|
|
total_deleted = delete_timestamp_rows_in_chunks(
|
|
self._with_db_connection,
|
|
'packet_stream',
|
|
'timestamp',
|
|
cutoff_time,
|
|
batch_size=batch_size,
|
|
pause_seconds=pause_seconds,
|
|
logger=self.logger,
|
|
progress_label='packet stream',
|
|
)
|
|
if total_deleted > 0:
|
|
self.logger.info(
|
|
f"Cleaned up {total_deleted} old packet stream entries "
|
|
f"(older than {days_to_keep} days)"
|
|
)
|
|
|
|
except sqlite3.OperationalError as e:
|
|
self.logger.warning(f"Database busy during cleanup (will retry next cycle): {e}")
|
|
except Exception as e:
|
|
self.logger.error(f"Error cleaning up old packet stream data: {e}", exc_info=True)
|