c2cae5665e
Root cause: Windows batch files written with LF endings caused cmd.exe to misparse labels and Chinese characters, producing garbled "not a command" errors. The Python launcher avoids encoding issues entirely. - start.py: reliable cross-platform launcher (kill ports, start 3 services, wait for health, print status) - start.bat / start_all.bat: minimal 4-line ASCII wrappers - stop.bat: inline Python for port-based process killing
133 lines
4.0 KiB
Python
133 lines
4.0 KiB
Python
"""Start all jrxml-agent services (validator, API, frontend)."""
|
|
import subprocess
|
|
import sys
|
|
import time
|
|
import urllib.request
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).parent
|
|
VENV_PYTHON = ROOT / ".venv" / "Scripts" / "python.exe"
|
|
FRONTEND_DIR = ROOT / "frontend"
|
|
|
|
|
|
def kill_port(port: int):
|
|
"""Kill any process listening on the given port."""
|
|
import os
|
|
import signal
|
|
try:
|
|
result = subprocess.run(
|
|
["netstat", "-ano"], capture_output=True, text=True
|
|
)
|
|
for line in result.stdout.splitlines():
|
|
if f":{port}" in line and "LISTENING" in line:
|
|
parts = line.split()
|
|
pid = int(parts[-1])
|
|
print(f" Killing PID {pid} on port {port}")
|
|
os.kill(pid, signal.SIGTERM)
|
|
except Exception as e:
|
|
print(f" (cleanup note: {e})")
|
|
|
|
|
|
def wait_http(url: str, timeout: int = 60, interval: float = 2.0) -> bool:
|
|
"""Wait until an HTTP endpoint responds 200, or timeout."""
|
|
deadline = time.time() + timeout
|
|
while time.time() < deadline:
|
|
try:
|
|
urllib.request.urlopen(url, timeout=2)
|
|
return True
|
|
except Exception:
|
|
time.sleep(interval)
|
|
return False
|
|
|
|
|
|
def wait_port(port: int, timeout: int = 60, interval: float = 3.0) -> bool:
|
|
"""Wait until a TCP port is listening."""
|
|
deadline = time.time() + timeout
|
|
while time.time() < deadline:
|
|
try:
|
|
result = subprocess.run(
|
|
["netstat", "-ano"], capture_output=True, text=True
|
|
)
|
|
for line in result.stdout.splitlines():
|
|
if f":{port}" in line and "LISTENING" in line:
|
|
return True
|
|
except Exception:
|
|
pass
|
|
time.sleep(interval)
|
|
return False
|
|
|
|
|
|
def main():
|
|
if not VENV_PYTHON.exists():
|
|
print("[ERROR] .venv not found. Create a virtual environment first.")
|
|
sys.exit(1)
|
|
|
|
print("=" * 48)
|
|
print(" jrxml-agent launcher (full stack)")
|
|
print("=" * 48)
|
|
|
|
# -- cleanup --
|
|
print("\n[Cleanup] Checking residual processes...")
|
|
for port in (8000, 8001, 5173):
|
|
kill_port(port)
|
|
|
|
# -- 1. Validator --
|
|
print("\n[1/3] Starting validator on :8001 ...")
|
|
subprocess.Popen(
|
|
[str(VENV_PYTHON), "-c",
|
|
"import uvicorn; uvicorn.run('validation_service.main:app',host='0.0.0.0',port=8001,reload=False)"],
|
|
cwd=str(ROOT),
|
|
creationflags=subprocess.CREATE_NO_WINDOW,
|
|
)
|
|
if not wait_http("http://localhost:8001/health"):
|
|
print("[FAIL] Validator did not start in time.")
|
|
sys.exit(1)
|
|
print(" :8001 ready")
|
|
|
|
# -- 2. API --
|
|
print("[2/3] Starting API on :8000 ...")
|
|
subprocess.Popen(
|
|
[str(VENV_PYTHON), "-c",
|
|
"import uvicorn; uvicorn.run('api_server:app',host='0.0.0.0',port=8000,reload=False)"],
|
|
cwd=str(ROOT),
|
|
creationflags=subprocess.CREATE_NO_WINDOW,
|
|
)
|
|
if not wait_http("http://localhost:8000/api/health"):
|
|
print("[FAIL] API server did not start in time.")
|
|
sys.exit(1)
|
|
print(" :8000 ready")
|
|
|
|
# -- 3. Frontend --
|
|
print("[3/3] Starting frontend on :5173 ...")
|
|
if not (FRONTEND_DIR / "node_modules").exists():
|
|
print(" Installing npm dependencies...")
|
|
subprocess.run(["npm", "install"], cwd=str(FRONTEND_DIR), check=True)
|
|
|
|
subprocess.Popen(
|
|
["npm", "run", "dev"],
|
|
cwd=str(FRONTEND_DIR),
|
|
creationflags=subprocess.CREATE_NO_WINDOW,
|
|
)
|
|
if not wait_port(5173):
|
|
print("[FAIL] Frontend did not start in time.")
|
|
sys.exit(1)
|
|
print(" :5173 ready")
|
|
|
|
print("\n" + "=" * 48)
|
|
print(" All services ready:")
|
|
print(" Frontend: http://localhost:5173")
|
|
print(" API: http://localhost:8000/docs")
|
|
print(" Validator: http://localhost:8001/health")
|
|
print(" Press Ctrl+C to stop all services")
|
|
print("=" * 48)
|
|
|
|
try:
|
|
while True:
|
|
time.sleep(1)
|
|
except KeyboardInterrupt:
|
|
print("\nShutting down...")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|