улучшенния в коде и исправление ошибок
This commit is contained in:
4
bot/tasks/__init__.py
Normal file
4
bot/tasks/__init__.py
Normal file
@@ -0,0 +1,4 @@
|
||||
"""
|
||||
Модуль фоновых задач для бота
|
||||
"""
|
||||
from .cleanup import *
|
||||
263
bot/tasks/cleanup.py
Normal file
263
bot/tasks/cleanup.py
Normal file
@@ -0,0 +1,263 @@
|
||||
"""
|
||||
Фоновые задачи для автоматической очистки и обслуживания бота
|
||||
"""
|
||||
import asyncio
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
|
||||
from database import get_manager
|
||||
from middleware.loggers import logger
|
||||
from configs import settings
|
||||
|
||||
__all__ = ('cleanup_expired_banwords', 'cleanup_spam_stats', 'auto_backup_database', 'start_background_tasks', 'check_system_health')
|
||||
|
||||
|
||||
async def cleanup_expired_banwords() -> None:
|
||||
"""
|
||||
Периодически удаляет истёкшие временные банворды.
|
||||
|
||||
Запускается каждый час и проверяет все временные слова.
|
||||
Удаляет те, у которых истёк срок действия.
|
||||
"""
|
||||
logger.info("🔄 Запущена задача автоочистки временных банвордов", log_type="CLEANUP")
|
||||
|
||||
manager = get_manager()
|
||||
|
||||
while True:
|
||||
try:
|
||||
# Ждём 1 час между проверками
|
||||
await asyncio.sleep(3600)
|
||||
|
||||
# Выполняем очистку
|
||||
deleted = await manager.cleanup_expired_temp_words()
|
||||
|
||||
if deleted > 0:
|
||||
logger.info(
|
||||
f"✅ Очищено {deleted} истёкших временных банвордов",
|
||||
log_type="CLEANUP"
|
||||
)
|
||||
else:
|
||||
logger.debug(
|
||||
"✓ Проверка временных банвордов: истёкших не найдено",
|
||||
log_type="CLEANUP"
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
f"❌ Ошибка в задаче очистки банвордов: {e}",
|
||||
log_type="CLEANUP"
|
||||
)
|
||||
# При ошибке ждём 5 минут перед следующей попыткой
|
||||
await asyncio.sleep(300)
|
||||
|
||||
|
||||
async def cleanup_spam_stats(max_age_days: int = 30) -> None:
|
||||
"""
|
||||
Очищает старую статистику антиспама.
|
||||
|
||||
Запускается каждые 24 часа и удаляет записи старше max_age_days дней.
|
||||
|
||||
Args:
|
||||
max_age_days: Возраст записей для удаления (по умолчанию 30 дней)
|
||||
"""
|
||||
logger.info(
|
||||
f"🔄 Запущена задача очистки статистики (возраст > {max_age_days} дней)",
|
||||
log_type="CLEANUP"
|
||||
)
|
||||
|
||||
from bot.middlewares.spam_mdw import spam_stats
|
||||
|
||||
while True:
|
||||
try:
|
||||
# Ждём 24 часа между проверками
|
||||
await asyncio.sleep(86400)
|
||||
|
||||
# Очищаем старую статистику
|
||||
max_age_seconds = max_age_days * 86400
|
||||
deleted = spam_stats.cleanup(max_age=max_age_seconds)
|
||||
|
||||
if deleted > 0:
|
||||
logger.info(
|
||||
f"✅ Очищена статистика: {deleted} неактивных пользователей",
|
||||
log_type="CLEANUP"
|
||||
)
|
||||
else:
|
||||
logger.debug(
|
||||
"✓ Проверка статистики: старых записей не найдено",
|
||||
log_type="CLEANUP"
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
f"❌ Ошибка в задаче очистки статистики: {e}",
|
||||
log_type="CLEANUP"
|
||||
)
|
||||
await asyncio.sleep(3600) # При ошибке ждём 1 час
|
||||
|
||||
|
||||
async def auto_backup_database(backup_interval_hours: int = 24, keep_backups: int = 7) -> None:
|
||||
"""
|
||||
Автоматически создаёт резервные копии базы данных.
|
||||
|
||||
Args:
|
||||
backup_interval_hours: Интервал между бэкапами (по умолчанию 24 часа)
|
||||
keep_backups: Количество хранимых копий (по умолчанию 7)
|
||||
"""
|
||||
logger.info(
|
||||
f"🔄 Запущена задача автобэкапа (каждые {backup_interval_hours}ч, хранить {keep_backups})",
|
||||
log_type="CLEANUP"
|
||||
)
|
||||
|
||||
while True:
|
||||
try:
|
||||
# Ждём указанное время
|
||||
await asyncio.sleep(backup_interval_hours * 3600)
|
||||
|
||||
# Путь к базе данных
|
||||
db_path = Path(settings.DATABASE_PATH)
|
||||
|
||||
if not db_path.exists():
|
||||
logger.warning(
|
||||
f"⚠️ База данных не найдена: {db_path}",
|
||||
log_type="CLEANUP"
|
||||
)
|
||||
continue
|
||||
|
||||
# Создаём папку для бэкапов
|
||||
backup_dir = Path("backups")
|
||||
backup_dir.mkdir(exist_ok=True)
|
||||
|
||||
# Имя файла бэкапа с датой и временем
|
||||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
backup_path = backup_dir / f"banwords_backup_{timestamp}.db"
|
||||
|
||||
# Копируем базу данных
|
||||
shutil.copy2(db_path, backup_path)
|
||||
|
||||
# Получаем размер файла
|
||||
backup_size = backup_path.stat().st_size / 1024 # KB
|
||||
|
||||
logger.info(
|
||||
f"✅ Создан backup: {backup_path.name} ({backup_size:.1f} KB)",
|
||||
log_type="CLEANUP"
|
||||
)
|
||||
|
||||
# Удаляем старые бэкапы (оставляем только последние N)
|
||||
backups = sorted(backup_dir.glob("banwords_backup_*.db"))
|
||||
|
||||
if len(backups) > keep_backups:
|
||||
old_backups = backups[:-keep_backups]
|
||||
|
||||
for old_backup in old_backups:
|
||||
old_backup.unlink()
|
||||
logger.debug(
|
||||
f"🗑️ Удалён старый backup: {old_backup.name}",
|
||||
log_type="CLEANUP"
|
||||
)
|
||||
|
||||
logger.info(
|
||||
f"✓ Удалено старых бэкапов: {len(old_backups)}",
|
||||
log_type="CLEANUP"
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
f"❌ Ошибка создания backup: {e}",
|
||||
log_type="CLEANUP"
|
||||
)
|
||||
await asyncio.sleep(3600) # При ошибке ждём 1 час
|
||||
|
||||
|
||||
async def check_system_health() -> None:
|
||||
"""
|
||||
Мониторинг здоровья системы.
|
||||
|
||||
Проверяет каждые 5 минут:
|
||||
- Размер базы данных
|
||||
- Количество записей в БД
|
||||
- Использование памяти (статистика антиспама)
|
||||
"""
|
||||
logger.info("🔄 Запущена задача мониторинга системы", log_type="CLEANUP")
|
||||
|
||||
manager = get_manager()
|
||||
|
||||
while True:
|
||||
try:
|
||||
await asyncio.sleep(300) # 5 минут
|
||||
|
||||
# Проверяем размер БД
|
||||
db_path = Path(settings.DATABASE_PATH)
|
||||
if db_path.exists():
|
||||
db_size_mb = db_path.stat().st_size / (1024 * 1024)
|
||||
|
||||
if db_size_mb > 100: # Если больше 100 MB
|
||||
logger.warning(
|
||||
f"⚠️ Большой размер БД: {db_size_mb:.2f} MB",
|
||||
log_type="CLEANUP"
|
||||
)
|
||||
|
||||
# Проверяем количество временных слов
|
||||
stats = await manager.get_stats()
|
||||
temp_count = stats.get('temp_total', 0)
|
||||
|
||||
if temp_count > 100: # Если больше 100 временных слов
|
||||
logger.warning(
|
||||
f"⚠️ Много временных банвордов: {temp_count}",
|
||||
log_type="CLEANUP"
|
||||
)
|
||||
|
||||
# Проверяем статистику антиспама
|
||||
from bot.middlewares.spam_mdw import spam_stats
|
||||
spam_summary = spam_stats.get_stats_summary()
|
||||
|
||||
active_blocks = spam_summary.get('active_blocks', 0)
|
||||
if active_blocks > 10:
|
||||
logger.warning(
|
||||
f"⚠️ Много активных блокировок: {active_blocks}",
|
||||
log_type="CLEANUP"
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
f"❌ Ошибка в задаче мониторинга: {e}",
|
||||
log_type="CLEANUP"
|
||||
)
|
||||
await asyncio.sleep(600) # При ошибке ждём 10 минут
|
||||
|
||||
|
||||
def start_background_tasks() -> list[asyncio.Task]:
|
||||
"""
|
||||
Запускает все фоновые задачи.
|
||||
|
||||
Returns:
|
||||
List[asyncio.Task]: Список запущенных задач
|
||||
"""
|
||||
tasks = []
|
||||
|
||||
# 1. Автоочистка временных банвордов (каждый час)
|
||||
task1 = asyncio.create_task(cleanup_expired_banwords())
|
||||
tasks.append(task1)
|
||||
logger.info("✅ Задача 'cleanup_expired_banwords' запущена", log_type="STARTUP")
|
||||
|
||||
# 2. Очистка старой статистики (каждые 24 часа)
|
||||
task2 = asyncio.create_task(cleanup_spam_stats(max_age_days=30))
|
||||
tasks.append(task2)
|
||||
logger.info("✅ Задача 'cleanup_spam_stats' запущена", log_type="STARTUP")
|
||||
|
||||
# 3. Автобэкап базы данных (каждые 24 часа, хранить 7 копий)
|
||||
task3 = asyncio.create_task(auto_backup_database(backup_interval_hours=24, keep_backups=7))
|
||||
tasks.append(task3)
|
||||
logger.info("✅ Задача 'auto_backup_database' запущена", log_type="STARTUP")
|
||||
|
||||
# 4. Мониторинг здоровья системы (каждые 5 минут)
|
||||
task4 = asyncio.create_task(check_system_health())
|
||||
tasks.append(task4)
|
||||
logger.info("✅ Задача 'check_system_health' запущена", log_type="STARTUP")
|
||||
|
||||
logger.success(
|
||||
f"🚀 Все фоновые задачи запущены: {len(tasks)} шт.",
|
||||
log_type="STARTUP"
|
||||
)
|
||||
|
||||
return tasks
|
||||
Reference in New Issue
Block a user