- Added a new `/status` endpoint in `server_prometheus.py` to provide process status information, including uptime and resource usage metrics. - Implemented a PID manager in `run_helper.py` to track the bot's process, improving monitoring capabilities. - Introduced a method to delete audio moderation records in `audio_repository.py`, enhancing database management. - Updated voice message handling in callback handlers to ensure proper deletion of audio moderation records. - Improved error handling and logging in various services, ensuring better tracking of media processing and file downloads. - Refactored media handling functions to streamline operations and improve code readability. - Enhanced metrics tracking for file downloads and media processing, providing better insights into bot performance.
168 lines
7.4 KiB
Python
168 lines
7.4 KiB
Python
import asyncio
|
||
import os
|
||
import sys
|
||
import signal
|
||
|
||
# Ensure project root is on sys.path for module resolution
|
||
CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||
if CURRENT_DIR not in sys.path:
|
||
sys.path.insert(0, CURRENT_DIR)
|
||
|
||
from helper_bot.main import start_bot
|
||
from helper_bot.utils.base_dependency_factory import get_global_instance
|
||
from helper_bot.utils.auto_unban_scheduler import get_auto_unban_scheduler
|
||
from logs.custom_logger import logger
|
||
|
||
# Импортируем PID менеджер из инфраструктуры (если доступен)
|
||
import sys
|
||
import os
|
||
|
||
def get_pid_manager():
|
||
"""Получение PID менеджера из инфраструктуры проекта"""
|
||
try:
|
||
# Пытаемся импортировать из инфраструктуры проекта
|
||
infra_path = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), 'infra', 'monitoring')
|
||
if infra_path not in sys.path:
|
||
sys.path.insert(0, infra_path)
|
||
|
||
from pid_manager import get_bot_pid_manager
|
||
return get_bot_pid_manager
|
||
|
||
except ImportError:
|
||
# В изолированном запуске PID менеджер не нужен
|
||
logger.info("PID менеджер недоступен (изолированный запуск), PID файл не создается")
|
||
return None
|
||
|
||
# Получаем функцию создания PID менеджера
|
||
get_bot_pid_manager = get_pid_manager()
|
||
|
||
|
||
async def main():
|
||
"""Основная функция запуска"""
|
||
# Создаем PID менеджер для отслеживания процесса (если доступен)
|
||
pid_manager = None
|
||
if get_bot_pid_manager:
|
||
pid_manager = get_bot_pid_manager("helper_bot")
|
||
if not pid_manager.create_pid_file():
|
||
logger.error("Не удалось создать PID файл, завершаем работу")
|
||
return
|
||
else:
|
||
logger.info("PID менеджер недоступен, запуск без PID файла")
|
||
|
||
bdf = get_global_instance()
|
||
|
||
# Создаем бота для автоматического разбана
|
||
from aiogram import Bot
|
||
from aiogram.client.default import DefaultBotProperties
|
||
|
||
auto_unban_bot = Bot(
|
||
token=bdf.settings['Telegram']['bot_token'],
|
||
default=DefaultBotProperties(parse_mode='HTML'),
|
||
timeout=30.0
|
||
)
|
||
|
||
# Инициализируем планировщик автоматического разбана
|
||
auto_unban_scheduler = get_auto_unban_scheduler()
|
||
auto_unban_scheduler.set_bot(auto_unban_bot)
|
||
auto_unban_scheduler.start_scheduler()
|
||
|
||
# Метрики запускаются в main.py через server_prometheus.py
|
||
# Здесь не нужно дублировать функциональность
|
||
|
||
# Флаг для корректного завершения
|
||
shutdown_event = asyncio.Event()
|
||
|
||
def signal_handler(signum, frame):
|
||
"""Обработчик сигналов для корректного завершения"""
|
||
logger.info(f"Получен сигнал {signum}, завершаем работу...")
|
||
shutdown_event.set()
|
||
|
||
# Регистрируем обработчики сигналов
|
||
signal.signal(signal.SIGINT, signal_handler)
|
||
signal.signal(signal.SIGTERM, signal_handler)
|
||
|
||
# Запускаем бота (метрики запускаются внутри start_bot)
|
||
bot_task = asyncio.create_task(start_bot(bdf))
|
||
|
||
main_bot = None
|
||
|
||
try:
|
||
# Ждем сигнала завершения
|
||
await shutdown_event.wait()
|
||
logger.info("Начинаем корректное завершение...")
|
||
|
||
except KeyboardInterrupt:
|
||
logger.info("Получен сигнал завершения...")
|
||
finally:
|
||
logger.info("Останавливаем планировщик автоматического разбана...")
|
||
auto_unban_scheduler.stop_scheduler()
|
||
|
||
# Останавливаем планировщик метрик
|
||
try:
|
||
from helper_bot.utils.metrics_scheduler import stop_metrics_scheduler
|
||
stop_metrics_scheduler()
|
||
logger.info("Планировщик метрик остановлен")
|
||
except Exception as e:
|
||
logger.error(f"Ошибка при остановке планировщика метрик: {e}")
|
||
|
||
# Метрики останавливаются в main.py
|
||
|
||
logger.info("Останавливаем задачи...")
|
||
# Отменяем задачу бота
|
||
bot_task.cancel()
|
||
|
||
# Очищаем PID файл (если PID менеджер доступен)
|
||
if pid_manager:
|
||
pid_manager.cleanup_pid_file()
|
||
|
||
# Ждем завершения задачи бота и получаем результат main bot
|
||
try:
|
||
results = await asyncio.gather(bot_task, return_exceptions=True)
|
||
# Результат - это main bot
|
||
if results[0] and not isinstance(results[0], Exception):
|
||
main_bot = results[0]
|
||
except Exception as e:
|
||
logger.error(f"Ошибка при остановке задач: {e}")
|
||
|
||
# Закрываем сессию основного бота (если она еще не закрыта)
|
||
if main_bot and hasattr(main_bot, 'session') and not main_bot.session.closed:
|
||
try:
|
||
await main_bot.session.close()
|
||
logger.info("Сессия основного бота корректно закрыта")
|
||
except Exception as e:
|
||
logger.error(f"Ошибка при закрытии сессии основного бота: {e}")
|
||
|
||
# Закрываем сессию бота для автоматического разбана
|
||
if not auto_unban_bot.session.closed:
|
||
try:
|
||
await auto_unban_bot.session.close()
|
||
logger.info("Сессия бота автоматического разбана корректно закрыта")
|
||
except Exception as e:
|
||
logger.error(f"Ошибка при закрытии сессии бота автоматического разбана: {e}")
|
||
|
||
# Даем время на завершение всех aiohttp соединений
|
||
await asyncio.sleep(0.2)
|
||
|
||
logger.info("Бот корректно остановлен")
|
||
|
||
|
||
if __name__ == '__main__':
|
||
try:
|
||
asyncio.run(main())
|
||
except AttributeError:
|
||
# Fallback for Python 3.6-3.7
|
||
loop = asyncio.get_event_loop()
|
||
try:
|
||
loop.run_until_complete(main())
|
||
finally:
|
||
# Закрываем все pending tasks
|
||
pending = asyncio.all_tasks(loop)
|
||
for task in pending:
|
||
task.cancel()
|
||
|
||
# Ждем завершения всех задач
|
||
if pending:
|
||
loop.run_until_complete(asyncio.gather(*pending, return_exceptions=True))
|
||
|
||
loop.close()
|