diff --git a/backend/api/supervisor_account.py b/backend/api/supervisor_account.py index 475d800..1ea3993 100644 --- a/backend/api/supervisor_account.py +++ b/backend/api/supervisor_account.py @@ -125,7 +125,35 @@ def ini_filename_for_program(program_name: str) -> str: def render_program_ini(account_id: int, program_name: str) -> str: project_root = _get_project_root() - python_bin = sys.executable # 使用 backend 当前虚拟环境,通常已包含 trading_system 依赖 + # Python 可执行文件: + # - 优先使用 TRADING_PYTHON_BIN(线上可显式指定 trading_system 的 venv) + # - 否则尝试多种候选路径(避免 backend venv 未安装交易依赖导致启动失败) + python_bin_env = (os.getenv("TRADING_PYTHON_BIN") or "").strip() + candidates = [] + if python_bin_env: + candidates.append(python_bin_env) + # 当前进程 python(backend venv) + candidates.append(sys.executable) + # 常见 venv 位置 + candidates += [ + str(project_root / "backend" / ".venv" / "bin" / "python"), + str(project_root / ".venv" / "bin" / "python"), + str(project_root / "trading_system" / ".venv" / "bin" / "python"), + "/usr/bin/python3", + "/usr/local/bin/python3", + ] + python_bin = None + for c in candidates: + try: + p = Path(c) + if p.exists() and os.access(str(p), os.X_OK): + python_bin = str(p) + break + except Exception: + continue + if not python_bin: + # 最后兜底:写 sys.executable,让错误能在日志里体现 + python_bin = sys.executable # 日志目录可通过环境变量覆盖 log_dir = Path(os.getenv("TRADING_LOG_DIR", str(project_root / "logs"))).expanduser() @@ -141,6 +169,7 @@ def render_program_ini(account_id: int, program_name: str) -> str: # 默认不自动启动,避免“创建账号=立刻下单” autostart = (os.getenv("TRADING_AUTOSTART_DEFAULT", "false") or "false").lower() == "true" + run_user = (os.getenv("SUPERVISOR_RUN_USER") or "").strip() return "\n".join( [ @@ -152,11 +181,18 @@ def render_program_ini(account_id: int, program_name: str) -> str: "startsecs=3", "stopasgroup=true", "killasgroup=true", + "stopsignal=TERM", "", - f'environment=ATS_ACCOUNT_ID="{int(account_id)}",PYTHONUNBUFFERED="1"', + # 关键:PYTHONPATH 指向项目根,确保 -m trading_system.main 可导入 + f'environment=ATS_ACCOUNT_ID="{int(account_id)}",PYTHONUNBUFFERED="1",PYTHONPATH="{project_root}"', + (f"user={run_user}" if run_user else "").rstrip(), "", f"stdout_logfile={out_log}", f"stderr_logfile={err_log}", + "stdout_logfile_maxbytes=20MB", + "stdout_logfile_backups=5", + "stderr_logfile_maxbytes=20MB", + "stderr_logfile_backups=5", "", ] )