Remove PID management functionality from the bot, including related endpoints and references in the codebase. Update Dockerfile to optimize the build process by separating build and runtime stages. Enhance healthcheck implementation in Dockerfile to use Python instead of curl. Update README to reflect the removal of PID file management and related endpoints.

This commit is contained in:
2025-09-16 17:49:49 +03:00
parent dc4300c6f2
commit e8fa682926
7 changed files with 38 additions and 357 deletions

View File

@@ -7,7 +7,6 @@ from .logger import get_logger, setup_logging
from .metrics import MetricsService, get_metrics_service
from .metrics_updater import MetricsUpdater, get_metrics_updater, start_metrics_updater, stop_metrics_updater
from .db_metrics_decorator import track_db_operation, track_db_connection
from .pid_manager import PIDManager, get_pid_manager, cleanup_pid_file
from .logging_decorators import (
log_function_call, log_business_event, log_fsm_transition,
log_handler, log_service, log_business, log_fsm,
@@ -25,7 +24,6 @@ __all__ = [
'MetricsService', 'get_metrics_service',
'MetricsUpdater', 'get_metrics_updater', 'start_metrics_updater', 'stop_metrics_updater',
'track_db_operation', 'track_db_connection',
'PIDManager', 'get_pid_manager', 'cleanup_pid_file',
'log_function_call', 'log_business_event', 'log_fsm_transition',
'log_handler', 'log_service', 'log_business', 'log_fsm',
'log_quiet', 'log_middleware', 'log_utility',

View File

@@ -31,7 +31,6 @@ class HTTPServer:
self.app.router.add_get('/metrics', self.metrics_handler)
self.app.router.add_get('/health', self.health_handler)
self.app.router.add_get('/ready', self.ready_handler)
self.app.router.add_get('/status', self.status_handler)
self.app.router.add_get('/', self.root_handler)
async def metrics_handler(self, request: Request) -> Response:
@@ -167,95 +166,6 @@ class HTTPServer:
status=HTTP_STATUS_INTERNAL_SERVER_ERROR
)
async def status_handler(self, request: Request) -> Response:
"""Handle /status endpoint for process status information."""
try:
import os
import time
import psutil
# Получаем PID текущего процесса
current_pid = os.getpid()
try:
# Получаем информацию о процессе
process = psutil.Process(current_pid)
create_time = process.create_time()
uptime_seconds = time.time() - create_time
# Логируем для диагностики
import datetime
create_time_str = datetime.datetime.fromtimestamp(create_time).strftime('%Y-%m-%d %H:%M:%S')
current_time_str = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
logger.info(f"Process PID {current_pid}: created at {create_time_str}, current time {current_time_str}, uptime {uptime_seconds:.1f}s")
# Форматируем uptime
if uptime_seconds < 60:
uptime_str = f"{int(uptime_seconds)}с"
elif uptime_seconds < 3600:
minutes = int(uptime_seconds // 60)
uptime_str = f"{minutes}м"
elif uptime_seconds < 86400:
hours = int(uptime_seconds // 3600)
minutes = int((uptime_seconds % 3600) // 60)
uptime_str = f"{hours}ч {minutes}м"
else:
days = int(uptime_seconds // 86400)
hours = int((uptime_seconds % 86400) // 3600)
uptime_str = f"{days}д {hours}ч"
# Проверяем, что процесс активен
if process.is_running():
status = "running"
else:
status = "stopped"
# Формируем ответ
response_data = {
"status": status,
"pid": current_pid,
"uptime": uptime_str,
"memory_usage_mb": round(process.memory_info().rss / 1024 / 1024, 2),
"cpu_percent": process.cpu_percent(),
"timestamp": time.time()
}
import json
return Response(
text=json.dumps(response_data, ensure_ascii=False),
content_type='application/json',
status=200
)
except psutil.NoSuchProcess:
# Процесс не найден
response_data = {
"status": "not_found",
"error": "Process not found",
"timestamp": time.time()
}
import json
return Response(
text=json.dumps(response_data, ensure_ascii=False),
content_type='application/json',
status=404
)
except Exception as e:
logger.error(f"Status check failed: {e}")
import json
response_data = {
"status": "error",
"error": str(e),
"timestamp": time.time()
}
return Response(
text=json.dumps(response_data, ensure_ascii=False),
content_type='application/json',
status=500
)
async def root_handler(self, request: Request) -> Response:
"""Обработчик корневого эндпоинта"""
@@ -268,8 +178,7 @@ class HTTPServer:
"endpoints": {
"metrics": "/metrics",
"health": "/health",
"ready": "/ready",
"status": "/status"
"ready": "/ready"
},
"uptime": time.time() - self.start_time
}

View File

@@ -1,117 +0,0 @@
"""
PID менеджер для управления PID файлом процесса
"""
import os
import sys
from pathlib import Path
from typing import Optional
from loguru import logger
class PIDManager:
"""Менеджер для управления PID файлом процесса"""
def __init__(self, service_name: str = "anon_bot", pid_dir: str = "/tmp"):
self.service_name = service_name
self.pid_dir = Path(pid_dir)
self.pid_file_path = self.pid_dir / f"{service_name}.pid"
self.pid: Optional[int] = None
def create_pid_file(self) -> bool:
"""Создать PID файл"""
try:
# Создаем директорию для PID файлов, если она не существует
self.pid_dir.mkdir(parents=True, exist_ok=True)
# Проверяем, не запущен ли уже процесс
if self.pid_file_path.exists():
try:
with open(self.pid_file_path, 'r') as f:
existing_pid = int(f.read().strip())
# Проверяем, жив ли процесс с этим PID
if self._is_process_running(existing_pid):
logger.error(f"Процесс {self.service_name} уже запущен с PID {existing_pid}")
return False
else:
logger.warning(f"Найден устаревший PID файл для {existing_pid}, удаляем его")
self.pid_file_path.unlink()
except (ValueError, OSError) as e:
logger.warning(f"Не удалось прочитать существующий PID файл: {e}, удаляем его")
self.pid_file_path.unlink()
# Получаем PID текущего процесса
self.pid = os.getpid()
# Создаем PID файл
with open(self.pid_file_path, 'w') as f:
f.write(str(self.pid))
logger.info(f"PID файл создан: {self.pid_file_path} (PID: {self.pid})")
return True
except Exception as e:
logger.error(f"Не удалось создать PID файл: {e}")
return False
def cleanup_pid_file(self) -> None:
"""Очистить PID файл"""
try:
if self.pid_file_path.exists():
# Проверяем, что PID файл принадлежит нашему процессу
with open(self.pid_file_path, 'r') as f:
file_pid = int(f.read().strip())
if file_pid == self.pid:
self.pid_file_path.unlink()
logger.info(f"PID файл удален: {self.pid_file_path}")
else:
logger.warning(f"PID файл содержит другой PID ({file_pid}), не удаляем")
except Exception as e:
logger.error(f"Ошибка при удалении PID файла: {e}")
def get_pid(self) -> Optional[int]:
"""Получить PID процесса"""
return self.pid
def get_pid_file_path(self) -> Path:
"""Получить путь к PID файлу"""
return self.pid_file_path
def _is_process_running(self, pid: int) -> bool:
"""Проверить, запущен ли процесс с указанным PID"""
try:
# В Unix-системах отправляем сигнал 0 для проверки существования процесса
os.kill(pid, 0)
return True
except (OSError, ProcessLookupError):
return False
# Глобальный экземпляр PID менеджера
_pid_manager: Optional[PIDManager] = None
def get_pid_manager(service_name: str = "anon_bot", pid_dir: str = "/tmp") -> PIDManager:
"""Получить экземпляр PID менеджера"""
global _pid_manager
if _pid_manager is None:
_pid_manager = PIDManager(service_name, pid_dir)
return _pid_manager
def create_pid_file(service_name: str = "anon_bot", pid_dir: str = "/tmp") -> bool:
"""Создать PID файл"""
pid_manager = get_pid_manager(service_name, pid_dir)
return pid_manager.create_pid_file()
def cleanup_pid_file() -> None:
"""Очистить PID файл"""
if _pid_manager:
_pid_manager.cleanup_pid_file()