"""PM2 重启当前实例(仅 Linux 部署环境).""" from __future__ import annotations import os import shlex import subprocess import sys from typing import Any def default_pm2_app_name(exchange_key: str) -> str: mapping = { "okx": "crypto_okx", "binance": "crypto_binance", "gate": "crypto_gate", } return mapping.get((exchange_key or "").strip().lower(), "crypto_okx") def resolve_pm2_app_name(exchange_key: str) -> str: explicit = (os.getenv("PM2_APP_NAME") or "").strip() if explicit: return explicit return default_pm2_app_name(exchange_key) def schedule_pm2_restart(app_name: str, *, delay_seconds: float = 1.0) -> dict[str, Any]: """延迟触发 PM2 重启,便于 HTTP 响应先返回(避免重启当前进程导致请求中断).""" if not sys.platform.startswith("linux"): return {"ok": False, "msg": "仅 Linux 服务器支持 PM2 重启", "app": app_name} if not (app_name or "").strip(): return {"ok": False, "msg": "未指定 PM2 应用名", "app": app_name} app_name = app_name.strip() try: cmd = f"sleep {delay_seconds} && exec pm2 restart {shlex.quote(app_name)} --update-env" subprocess.Popen( ["bash", "-c", cmd], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, start_new_session=True, ) return {"ok": True, "app": app_name, "msg": "重启已触发", "deferred": True} except FileNotFoundError: return {"ok": False, "msg": "未找到 bash 或 pm2 命令", "app": app_name} except Exception as e: return {"ok": False, "msg": str(e), "app": app_name} def restart_instance_pm2(exchange_key: str, *, defer: bool = False) -> dict[str, Any]: if not sys.platform.startswith("linux"): return {"ok": False, "msg": "仅 Linux 服务器支持 PM2 重启", "app": None} app_name = resolve_pm2_app_name(exchange_key) if defer: return schedule_pm2_restart(app_name) try: proc = subprocess.run( ["pm2", "restart", app_name, "--update-env"], capture_output=True, text=True, timeout=120, ) ok = proc.returncode == 0 return { "ok": ok, "app": app_name, "msg": (proc.stdout or proc.stderr or "").strip()[:500], "returncode": proc.returncode, } except FileNotFoundError: return {"ok": False, "msg": "未找到 pm2 命令", "app": app_name} except subprocess.TimeoutExpired: return {"ok": False, "msg": "pm2 restart 超时", "app": app_name} except Exception as e: return {"ok": False, "msg": str(e), "app": app_name}