a
This commit is contained in:
parent
18cfeaf5db
commit
fe855df566
|
|
@ -592,6 +592,20 @@ def _parse_supervisor_status(raw: str) -> Tuple[bool, Optional[int], str]:
|
|||
return False, None, state
|
||||
return False, None, "UNKNOWN"
|
||||
|
||||
def _list_supervisor_process_names(status_all_raw: str) -> list[str]:
|
||||
names: list[str] = []
|
||||
if not status_all_raw:
|
||||
return names
|
||||
for ln in status_all_raw.splitlines():
|
||||
s = (ln or "").strip()
|
||||
if not s:
|
||||
continue
|
||||
# 每行格式:<name> <STATE> ...
|
||||
name = s.split(None, 1)[0].strip()
|
||||
if name:
|
||||
names.append(name)
|
||||
return names
|
||||
|
||||
|
||||
def _get_program_name() -> str:
|
||||
# 你给的宝塔配置是 [program:auto_sys]
|
||||
|
|
@ -880,6 +894,99 @@ async def trading_restart(_admin: Dict[str, Any] = Depends(require_system_admin)
|
|||
raise HTTPException(status_code=500, detail=f"supervisorctl restart 失败: {e}")
|
||||
|
||||
|
||||
@router.post("/trading/restart-all")
|
||||
async def trading_restart_all(
|
||||
_admin: Dict[str, Any] = Depends(require_system_admin),
|
||||
prefix: str = "auto_sys_acc",
|
||||
include_default: bool = False,
|
||||
do_update: bool = True,
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
一键重启所有账号交易进程(supervisor)。
|
||||
|
||||
- 默认重启所有以 auto_sys_acc 开头的 program(例如 auto_sys_acc1/2/3...)
|
||||
- 可选 include_default=true:同时包含 SUPERVISOR_TRADING_PROGRAM(默认 auto_sys)
|
||||
- 可选 do_update=true:先执行 supervisorctl reread/update 再重启(确保新 ini 生效)
|
||||
"""
|
||||
try:
|
||||
prefix = (prefix or "auto_sys_acc").strip()
|
||||
if not prefix:
|
||||
prefix = "auto_sys_acc"
|
||||
|
||||
# 先读取全量 status,拿到有哪些进程
|
||||
status_all = _run_supervisorctl(["status"])
|
||||
names = _list_supervisor_process_names(status_all)
|
||||
|
||||
targets: list[str] = []
|
||||
for n in names:
|
||||
if n.startswith(prefix):
|
||||
targets.append(n)
|
||||
|
||||
if include_default:
|
||||
default_prog = _get_program_name()
|
||||
if default_prog and default_prog not in targets and default_prog in names:
|
||||
targets.append(default_prog)
|
||||
|
||||
if not targets:
|
||||
return {
|
||||
"message": "未找到可重启的交易进程",
|
||||
"prefix": prefix,
|
||||
"include_default": include_default,
|
||||
"count": 0,
|
||||
"targets": [],
|
||||
"status_all": status_all,
|
||||
}
|
||||
|
||||
reread_out = ""
|
||||
update_out = ""
|
||||
if do_update:
|
||||
try:
|
||||
reread_out = _run_supervisorctl(["reread"])
|
||||
except Exception as e:
|
||||
reread_out = f"failed: {e}"
|
||||
try:
|
||||
update_out = _run_supervisorctl(["update"])
|
||||
except Exception as e:
|
||||
update_out = f"failed: {e}"
|
||||
|
||||
results: list[Dict[str, Any]] = []
|
||||
ok = 0
|
||||
failed = 0
|
||||
for prog in targets:
|
||||
try:
|
||||
out = _run_supervisorctl(["restart", prog])
|
||||
raw = _run_supervisorctl(["status", prog])
|
||||
running, pid, state = _parse_supervisor_status(raw)
|
||||
results.append(
|
||||
{
|
||||
"program": prog,
|
||||
"ok": True,
|
||||
"output": out,
|
||||
"status": {"running": running, "pid": pid, "state": state, "raw": raw},
|
||||
}
|
||||
)
|
||||
ok += 1
|
||||
except Exception as e:
|
||||
failed += 1
|
||||
results.append({"program": prog, "ok": False, "error": str(e)})
|
||||
|
||||
return {
|
||||
"message": "已发起批量重启",
|
||||
"prefix": prefix,
|
||||
"include_default": include_default,
|
||||
"do_update": do_update,
|
||||
"count": len(targets),
|
||||
"ok": ok,
|
||||
"failed": failed,
|
||||
"reread": reread_out,
|
||||
"update": update_out,
|
||||
"targets": targets,
|
||||
"results": results,
|
||||
}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"批量重启失败: {e}")
|
||||
|
||||
|
||||
@router.get("/backend/status")
|
||||
async def backend_status(_admin: Dict[str, Any] = Depends(require_system_admin)) -> Dict[str, Any]:
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -379,6 +379,20 @@ const ConfigPanel = ({ currentUser }) => {
|
|||
}
|
||||
}
|
||||
|
||||
const handleRestartAllTrading = async () => {
|
||||
if (!window.confirm('确定要重启【所有账号】的交易进程吗?这会让所有用户的交易服务短暂中断(约 3-10 秒),用于升级代码后统一生效。')) return
|
||||
setSystemBusy(true)
|
||||
setMessage('')
|
||||
try {
|
||||
const res = await api.restartAllTradingSystems({ prefix: 'auto_sys_acc', do_update: true })
|
||||
setMessage(`已发起批量重启:共 ${res.count} 个,成功 ${res.ok},失败 ${res.failed}`)
|
||||
} catch (e) {
|
||||
setMessage('批量重启失败: ' + (e?.message || '未知错误'))
|
||||
} finally {
|
||||
setSystemBusy(false)
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
loadConfigs()
|
||||
checkFeasibility()
|
||||
|
|
@ -972,6 +986,15 @@ const ConfigPanel = ({ currentUser }) => {
|
|||
>
|
||||
重启交易系统
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="system-btn primary"
|
||||
onClick={handleRestartAllTrading}
|
||||
disabled={systemBusy}
|
||||
title="批量重启所有账号交易进程(auto_sys_acc*),用于代码升级后统一生效"
|
||||
>
|
||||
重启所有账号交易
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="system-btn primary"
|
||||
|
|
|
|||
|
|
@ -508,6 +508,25 @@ export const api = {
|
|||
return response.json();
|
||||
},
|
||||
|
||||
restartAllTradingSystems: async (opts = {}) => {
|
||||
const params = new URLSearchParams()
|
||||
if (opts?.prefix) params.set('prefix', String(opts.prefix))
|
||||
if (opts?.include_default) params.set('include_default', 'true')
|
||||
if (opts?.do_update === false) params.set('do_update', 'false')
|
||||
const url = params.toString()
|
||||
? `${buildUrl('/api/system/trading/restart-all')}?${params.toString()}`
|
||||
: buildUrl('/api/system/trading/restart-all')
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: withAccountHeaders({ 'Content-Type': 'application/json' }),
|
||||
})
|
||||
if (!response.ok) {
|
||||
const error = await response.json().catch(() => ({ detail: '批量重启失败' }))
|
||||
throw new Error(error.detail || '批量重启失败')
|
||||
}
|
||||
return response.json()
|
||||
},
|
||||
|
||||
// 后端控制(uvicorn)
|
||||
getBackendStatus: async () => {
|
||||
const response = await fetch(buildUrl('/api/system/backend/status'), { headers: withAccountHeaders() });
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user