#!/usr/bin/env python3 # server_manager.py - Скрипт для управления сервером в фоновом режиме import os import sys import signal import subprocess import time import atexit from pathlib import Path # Конфигурация PID_FILE = "server.pid" LOG_FILE = "server.log" ERROR_LOG = "server_error.log" PYTHON_CMD = sys.executable SERVER_SCRIPT = "server.py" class ServerManager: def __init__(self): self.pid_file = Path(PID_FILE) self.log_file = Path(LOG_FILE) self.error_log = Path(ERROR_LOG) def is_running(self): """Проверка, запущен ли сервер""" if not self.pid_file.exists(): return False try: with open(self.pid_file, 'r') as f: pid = int(f.read().strip()) # Проверяем, существует ли процесс os.kill(pid, 0) return True except (OSError, ValueError, ProcessLookupError): # PID файл существует, но процесс не найден self.pid_file.unlink(missing_ok=True) return False def get_pid(self): """Получить PID сервера""" if not self.pid_file.exists(): return None try: with open(self.pid_file, 'r') as f: return int(f.read().strip()) except: return None def start(self): """Запуск сервера в фоновом режиме""" if self.is_running(): print(f"❌ Сервер уже запущен (PID: {self.get_pid()})") return False print("🚀 Запуск сервера в фоновом режиме...") try: # Открываем файлы для логов log_fd = open(self.log_file, 'a') err_fd = open(self.error_log, 'a') # Запускаем процесс process = subprocess.Popen( [PYTHON_CMD, SERVER_SCRIPT], stdout=log_fd, stderr=err_fd, stdin=subprocess.DEVNULL, start_new_session=True, # Отдельная сессия для фонового процесса cwd=os.path.dirname(os.path.abspath(__file__)) ) # Сохраняем PID with open(self.pid_file, 'w') as f: f.write(str(process.pid)) # Небольшая задержка для проверки запуска time.sleep(2) if self.is_running(): print(f"✅ Сервер успешно запущен (PID: {process.pid})") print(f"📝 Логи: {self.log_file}") print(f"❌ Логи ошибок: {self.error_log}") return True else: print("❌ Сервер не запустился") return False except Exception as e: print(f"❌ Ошибка при запуске: {e}") return False def stop(self): """Остановка сервера""" if not self.is_running(): print("❌ Сервер не запущен") return False pid = self.get_pid() print(f"🛑 Остановка сервера (PID: {pid})...") try: # Отправляем SIGTERM os.kill(pid, signal.SIGTERM) # Ждем завершения timeout = 10 for _ in range(timeout): time.sleep(1) if not self.is_running(): print("✅ Сервер остановлен") self.pid_file.unlink(missing_ok=True) return True # Если не остановился, принудительно завершаем print("⚠️ Сервер не отвечает, принудительное завершение...") os.kill(pid, signal.SIGKILL) time.sleep(1) if not self.is_running(): print("✅ Сервер принудительно остановлен") self.pid_file.unlink(missing_ok=True) return True else: print("❌ Не удалось остановить сервер") return False except ProcessLookupError: print("⚠️ Процесс не найден, удаляем PID файл") self.pid_file.unlink(missing_ok=True) return True except Exception as e: print(f"❌ Ошибка при остановке: {e}") return False def restart(self): """Перезапуск сервера""" print("🔄 Перезапуск сервера...") if self.is_running(): self.stop() time.sleep(2) return self.start() def status(self): """Статус сервера""" if self.is_running(): pid = self.get_pid() print(f"✅ Сервер запущен (PID: {pid})") print(f"📝 Логи: {self.log_file} ({self.log_file.stat().st_size} bytes)") print( f"❌ Логи ошибок: {self.error_log} ({self.error_log.stat().st_size if self.error_log.exists() else 0} bytes)") # Показываем последние строки лога if self.log_file.exists(): print("\n📋 Последние строки лога:") with open(self.log_file, 'r') as f: lines = f.readlines() for line in lines[-5:]: print(f" {line.strip()}") return True else: print("❌ Сервер не запущен") return False def logs(self, lines=20): """Показать последние строки лога""" if not self.log_file.exists(): print("📝 Лог файл не найден") return print(f"📋 Последние {lines} строк лога:") print("-" * 50) with open(self.log_file, 'r') as f: all_lines = f.readlines() for line in all_lines[-lines:]: print(line.strip()) def errors(self, lines=20): """Показать последние строки лога ошибок""" if not self.error_log.exists(): print("❌ Лог ошибок не найден") return print(f"⚠️ Последние {lines} строк лога ошибок:") print("-" * 50) with open(self.error_log, 'r') as f: all_lines = f.readlines() for line in all_lines[-lines:]: print(line.strip()) def main(): manager = ServerManager() if len(sys.argv) < 2: print("Использование:") print(" python server_manager.py start - запустить сервер") print(" python server_manager.py stop - остановить сервер") print(" python server_manager.py restart - перезапустить сервер") print(" python server_manager.py status - статус сервера") print(" python server_manager.py logs - показать логи") print(" python server_manager.py errors - показать ошибки") return command = sys.argv[1].lower() if command == 'start': manager.start() elif command == 'stop': manager.stop() elif command == 'restart': manager.restart() elif command == 'status': manager.status() elif command == 'logs': lines = int(sys.argv[2]) if len(sys.argv) > 2 else 20 manager.logs(lines) elif command == 'errors': lines = int(sys.argv[2]) if len(sys.argv) > 2 else 20 manager.errors(lines) else: print(f"❌ Неизвестная команда: {command}") if __name__ == "__main__": main()