diff --git a/apps/jingrow/jingrow/api/system.py b/apps/jingrow/jingrow/api/system.py index 52dc96c..79b4533 100644 --- a/apps/jingrow/jingrow/api/system.py +++ b/apps/jingrow/jingrow/api/system.py @@ -294,37 +294,55 @@ async def restart_environment(request: Request): is_production = str(getattr(settings, "environment", "development")).lower() == "production" reload_enabled = (not is_production) and bool(getattr(settings, "backend_reload", True)) + # 最佳实践:开发环境优先使用 reload,生产环境使用命令重启 if reload_enabled: # 开发模式:通过修改被监控的 Python 文件时间戳来触发 uvicorn reload + # 这是最快、最轻量的方式,不需要重启整个进程 try: - # 获取当前文件路径(system.py 在 reload_dir 中) current_file = Path(__file__) - - # 修改文件时间戳来触发 uvicorn 的文件变化检测 - # 这会触发 uvicorn 的自动重启 current_time = os.path.getmtime(current_file) - # touch 文件:更新访问和修改时间 + # 修改文件时间戳触发 uvicorn 的文件变化检测,自动重启 os.utime(current_file, (current_time + 1, current_time + 1)) - - logger.info(f"已通过修改文件时间戳触发 uvicorn reload,系统将在稍后自动重启") + logger.info("已通过文件时间戳触发 uvicorn reload,系统将在稍后自动重启") + return # 成功则直接返回 except Exception as e: - logger.error(f"通过文件时间戳触发重启失败: {str(e)}") - # 回退到信号方式 - try: - current_pid = os.getpid() - os.kill(current_pid, signal.SIGTERM) - logger.info("已发送重启信号") - except Exception as sig_error: - logger.error(f"发送重启信号也失败: {str(sig_error)}") - else: - # 生产模式:发送信号 + logger.warning(f"通过文件时间戳触发重启失败: {str(e)},将尝试命令重启") + + # 回退方案:使用命令重启(更可靠,适用于生产环境或 reload 失败时) + try: + import subprocess + from jingrow.utils.path import get_root_path + + root_path = get_root_path() + dev_script = root_path / "dev.sh" + + if dev_script.exists(): + # 只重启后端,不重启前端 + # 在后台执行,避免阻塞 + subprocess.Popen( + ["bash", str(dev_script), "backend"], + cwd=str(root_path), + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + start_new_session=True # 在新会话中运行,避免被父进程关闭 + ) + logger.info("已执行后端重启命令") + else: + # 如果 dev.sh 不存在,尝试直接重启当前进程 + logger.warning("未找到 dev.sh 脚本,尝试发送重启信号") + current_pid = os.getpid() + os.kill(current_pid, signal.SIGTERM) + logger.info("已发送重启信号") + except Exception as e: + logger.error(f"命令重启失败: {str(e)}") + # 最后的回退:发送信号 try: current_pid = os.getpid() os.kill(current_pid, signal.SIGTERM) - logger.info("生产模式:已发送重启信号") - except Exception as e: - logger.error(f"发送重启信号失败: {str(e)}") - logger.warning("无法通过信号重启,请手动重启服务") + logger.info("已发送重启信号(最后回退方案)") + except Exception as sig_error: + logger.error(f"所有重启方式都失败: {str(sig_error)}") + logger.warning("无法自动重启,请手动重启服务") # 启动后台任务 asyncio.create_task(delayed_restart())