feat: FastAPI+SSE API server, JRXML auto-reorder, session integrity fixes
This commit is contained in:
@@ -0,0 +1,144 @@
|
||||
"""
|
||||
agent_jrxml 统一启动/停止脚本
|
||||
用法: python start.py [--frontend]
|
||||
"""
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
import signal
|
||||
import os
|
||||
import socket
|
||||
|
||||
PROCESSES = []
|
||||
|
||||
def kill_port(port):
|
||||
"""杀掉占用指定端口的所有进程"""
|
||||
killed = []
|
||||
try:
|
||||
result = subprocess.run(
|
||||
['netstat', '-ano'], capture_output=True, text=True, timeout=10
|
||||
)
|
||||
for line in result.stdout.splitlines():
|
||||
if f':{port}' in line and 'LISTENING' in line:
|
||||
parts = line.strip().split()
|
||||
pid = parts[-1]
|
||||
try:
|
||||
subprocess.run(['taskkill', '/F', '/PID', pid],
|
||||
capture_output=True, timeout=5)
|
||||
killed.append(pid)
|
||||
except:
|
||||
pass
|
||||
except:
|
||||
pass
|
||||
if killed:
|
||||
print(f"[清理] 端口 {port} 已清理 {len(killed)} 个进程: {', '.join(killed)}")
|
||||
return len(killed)
|
||||
|
||||
|
||||
def wait_port(port, timeout=30):
|
||||
"""等待端口就绪"""
|
||||
for i in range(timeout * 2):
|
||||
try:
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.settimeout(1)
|
||||
s.connect(('127.0.0.1', port))
|
||||
s.close()
|
||||
return True
|
||||
except:
|
||||
time.sleep(0.5)
|
||||
return False
|
||||
|
||||
|
||||
def start(port, module, cwd=None):
|
||||
"""启动一个 uvicorn 服务"""
|
||||
cmd = [
|
||||
sys.executable, '-c',
|
||||
f"import uvicorn; uvicorn.run('{module}', host='0.0.0.0', port={port}, reload=False)"
|
||||
]
|
||||
proc = subprocess.Popen(cmd, cwd=cwd)
|
||||
PROCESSES.append((port, proc))
|
||||
print(f"[启动] {module} -> :{port} (PID: {proc.pid})")
|
||||
return proc
|
||||
|
||||
|
||||
def cleanup():
|
||||
"""清理所有子进程"""
|
||||
print("\n[清理] 正在停止所有服务...")
|
||||
for port, proc in PROCESSES:
|
||||
try:
|
||||
proc.terminate()
|
||||
except:
|
||||
pass
|
||||
time.sleep(2)
|
||||
for port, proc in PROCESSES:
|
||||
try:
|
||||
proc.kill()
|
||||
except:
|
||||
pass
|
||||
kill_port(port)
|
||||
print("[清理] 完成")
|
||||
|
||||
|
||||
def main():
|
||||
frontend = '--frontend' in sys.argv
|
||||
|
||||
# 1. 清理残留进程
|
||||
print("=" * 50)
|
||||
print("agent_jrxml 启动脚本")
|
||||
print("=" * 50)
|
||||
kill_port(8000)
|
||||
kill_port(8001)
|
||||
if frontend:
|
||||
kill_port(5173)
|
||||
|
||||
# 2. 启动服务(基于脚本所在目录自动定位项目)
|
||||
project = os.path.dirname(os.path.abspath(__file__))
|
||||
start(8000, 'api_server:app', cwd=project)
|
||||
start(8001, 'validation_service.main:app', cwd=project)
|
||||
|
||||
if frontend:
|
||||
# 前端用 npm 启动
|
||||
frontend_dir = os.path.join(project, 'frontend')
|
||||
proc = subprocess.Popen(
|
||||
['npm', 'run', 'dev'], cwd=frontend_dir,
|
||||
shell=True
|
||||
)
|
||||
PROCESSES.append((5173, proc))
|
||||
print(f"[启动] frontend (Vite) -> :5173")
|
||||
|
||||
# 3. 等待就绪
|
||||
print("\n[等待] 等待服务就绪...")
|
||||
ok = True
|
||||
for port, _ in PROCESSES:
|
||||
if wait_port(port):
|
||||
print(f" :{port} ✓")
|
||||
else:
|
||||
print(f" :{port} ✗ 超时!")
|
||||
ok = False
|
||||
|
||||
if not ok:
|
||||
print("\n[错误] 部分服务启动失败")
|
||||
cleanup()
|
||||
sys.exit(1)
|
||||
|
||||
print(f"\n{'='*50}")
|
||||
print("服务就绪:")
|
||||
print(f" API: http://localhost:8000/docs")
|
||||
print(f" 验证: http://localhost:8001/health")
|
||||
if frontend:
|
||||
print(f" 前端: http://localhost:5173")
|
||||
print(f"\n按 Ctrl+C 停止所有服务")
|
||||
print(f"{'='*50}")
|
||||
|
||||
# 4. 等待退出信号
|
||||
try:
|
||||
while True:
|
||||
time.sleep(1)
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
finally:
|
||||
cleanup()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user