#!/usr/bin/env python3 """ LQAdminPlatform 服务启动脚本 用于启动 FastAPI 应用服务器 """ import sys import os import socket import logging # 添加项目根目录到Python路径 project_root = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, project_root) sys.path.insert(0, os.path.join(project_root, 'src')) # 导入配置 from src.app.core.config import config_handler def check_port(host: str, port: int) -> bool: """ 检查端口是否可用 Args: host: 主机地址 port: 端口号 Returns: bool: 端口可用返回True,否则返回False """ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: try: s.bind((host, port)) return True except OSError: return False def find_available_port(host: str, start_port: int = 8000, max_port: int = 8010) -> int: """ 查找可用端口 Args: host: 主机地址 start_port: 起始端口 max_port: 最大端口 Returns: int: 可用端口号,如果没有找到返回None """ for port in range(start_port, max_port + 1): if check_port(host, port): return port return None def main(): """主函数:启动服务器""" import uvicorn # 配置日志 logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' ) logger = logging.getLogger(__name__) # 获取配置 host = config_handler.get("admin_app", "HOST", "0.0.0.0") port = config_handler.get_int("admin_app", "PORT", 8000) reload = config_handler.get_bool("admin_app", "RELOAD", True) debug = config_handler.get_bool("admin_app", "DEBUG", True) logger.info(f"host={host},port={port}") # 检查端口是否可用 if not check_port(host, port): logger.warning(f"⚠️ 端口 {port} 已被占用,正在查找可用端口...") available_port = find_available_port(host, port, port + 10) if available_port: port = available_port logger.info(f"✅ 找到可用端口: {port}") else: logger.error(f"❌ 未找到可用端口 (尝试范围: {port}-{port+10})") logger.error("请检查是否有其他服务占用了端口,或手动指定其他端口") sys.exit(1) # 打印启动信息 logger.info("=" * 70) logger.info(f"🚀 正在启动 {config_handler.get('admin_app', 'APP_NAME', '后台管理')} v{config_handler.get('admin_app', 'APP_VERSION', '1.0.0')}") logger.info("=" * 70) logger.info(f"📍 服务地址: http://{host}:{port}") logger.info(f"📚 API文档: http://{host}:{port}/docs") logger.info(f"📖 ReDoc文档: http://{host}:{port}/redoc") logger.info(f"🔧 调试模式: {'开启' if debug else '关闭'}") logger.info(f"🔄 热重载: {'开启' if reload else '关闭'}") logger.info("=" * 70) # 启动服务器 try: # 排除 logs 目录,避免写日志导致热重载进入死循环 reload_dirs = [os.path.join(project_root, "src")] if reload else None uvicorn.run( "src.app.server.app:app", host=host, port=port, reload=reload, reload_dirs=reload_dirs, log_level=config_handler.get("admin_app", "LOG_LEVEL", "INFO").lower(), access_log=True, use_colors=True ) except KeyboardInterrupt: logger.info("\n👋 服务已停止") except Exception as e: logger.error(f"❌ 服务启动失败: {e}", exc_info=True) sys.exit(1) if __name__ == "__main__": main()