run_server.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. #!/usr/bin/env python3
  2. """
  3. LQAdminPlatform 服务启动脚本
  4. 用于启动 FastAPI 应用服务器
  5. """
  6. import sys
  7. import os
  8. import socket
  9. import logging
  10. # 添加项目根目录到Python路径
  11. project_root = os.path.dirname(os.path.abspath(__file__))
  12. sys.path.insert(0, project_root)
  13. sys.path.insert(0, os.path.join(project_root, 'src'))
  14. # 导入配置
  15. from src.app.core.config import config_handler
  16. def check_port(host: str, port: int) -> bool:
  17. """
  18. 检查端口是否可用
  19. Args:
  20. host: 主机地址
  21. port: 端口号
  22. Returns:
  23. bool: 端口可用返回True,否则返回False
  24. """
  25. with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
  26. try:
  27. s.bind((host, port))
  28. return True
  29. except OSError:
  30. return False
  31. def find_available_port(host: str, start_port: int = 8000, max_port: int = 8010) -> int:
  32. """
  33. 查找可用端口
  34. Args:
  35. host: 主机地址
  36. start_port: 起始端口
  37. max_port: 最大端口
  38. Returns:
  39. int: 可用端口号,如果没有找到返回None
  40. """
  41. for port in range(start_port, max_port + 1):
  42. if check_port(host, port):
  43. return port
  44. return None
  45. def main():
  46. """主函数:启动服务器"""
  47. import uvicorn
  48. # 配置日志
  49. logging.basicConfig(
  50. level=logging.INFO,
  51. format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
  52. )
  53. logger = logging.getLogger(__name__)
  54. # 获取配置
  55. host = config_handler.get("admin_app", "HOST", "0.0.0.0")
  56. port = config_handler.get_int("admin_app", "PORT", 8000)
  57. reload = config_handler.get_bool("admin_app", "RELOAD", True)
  58. debug = config_handler.get_bool("admin_app", "DEBUG", True)
  59. logger.info(f"host={host},port={port}")
  60. # 检查端口是否可用
  61. if not check_port(host, port):
  62. logger.warning(f"⚠️ 端口 {port} 已被占用,正在查找可用端口...")
  63. available_port = find_available_port(host, port, port + 10)
  64. if available_port:
  65. port = available_port
  66. logger.info(f"✅ 找到可用端口: {port}")
  67. else:
  68. logger.error(f"❌ 未找到可用端口 (尝试范围: {port}-{port+10})")
  69. logger.error("请检查是否有其他服务占用了端口,或手动指定其他端口")
  70. sys.exit(1)
  71. # 打印启动信息
  72. logger.info("=" * 70)
  73. logger.info(f"🚀 正在启动 {config_handler.get('admin_app', 'APP_NAME', '后台管理')} v{config_handler.get('admin_app', 'APP_VERSION', '1.0.0')}")
  74. logger.info("=" * 70)
  75. logger.info(f"📍 服务地址: http://{host}:{port}")
  76. logger.info(f"📚 API文档: http://{host}:{port}/docs")
  77. logger.info(f"📖 ReDoc文档: http://{host}:{port}/redoc")
  78. logger.info(f"🔧 调试模式: {'开启' if debug else '关闭'}")
  79. logger.info(f"🔄 热重载: {'开启' if reload else '关闭'}")
  80. logger.info("=" * 70)
  81. # 启动服务器
  82. try:
  83. # 排除 logs 目录,避免写日志导致热重载进入死循环
  84. reload_dirs = [os.path.join(project_root, "src")] if reload else None
  85. uvicorn.run(
  86. "src.app.server.app:app",
  87. host=host,
  88. port=port,
  89. reload=reload,
  90. reload_dirs=reload_dirs,
  91. log_level=config_handler.get("admin_app", "LOG_LEVEL", "INFO").lower(),
  92. access_log=True,
  93. use_colors=True
  94. )
  95. except KeyboardInterrupt:
  96. logger.info("\n👋 服务已停止")
  97. except Exception as e:
  98. logger.error(f"❌ 服务启动失败: {e}", exc_info=True)
  99. sys.exit(1)
  100. if __name__ == "__main__":
  101. main()