121 lines
3.5 KiB
Python
121 lines
3.5 KiB
Python
"""Kill port 8001 holders, then start ai-service."""
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
import time
|
|
import urllib.request
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
LOG = ROOT / ".runtime" / "logs"
|
|
LOG.mkdir(parents=True, exist_ok=True)
|
|
|
|
|
|
def pids_on_port(port: int) -> list[int]:
|
|
out = subprocess.check_output(["netstat", "-ano"], text=True, errors="replace")
|
|
pids: set[int] = set()
|
|
needle = f":{port}"
|
|
for line in out.splitlines():
|
|
if needle not in line:
|
|
continue
|
|
if "LISTENING" not in line.upper():
|
|
continue
|
|
parts = line.split()
|
|
try:
|
|
pids.add(int(parts[-1]))
|
|
except ValueError:
|
|
pass
|
|
return sorted(pids)
|
|
|
|
|
|
def kill_pid(pid: int) -> None:
|
|
if pid <= 0:
|
|
return
|
|
subprocess.run(["taskkill", "/F", "/T", "/PID", str(pid)], check=False, capture_output=True)
|
|
|
|
|
|
def main() -> None:
|
|
print("stopping old ai...")
|
|
# stop watchdog first if present
|
|
wd = LOG / "watchdog.pid"
|
|
if wd.is_file():
|
|
try:
|
|
kill_pid(int(wd.read_text(encoding="ascii").strip()))
|
|
except ValueError:
|
|
pass
|
|
wd.unlink(missing_ok=True)
|
|
|
|
for name in ("ai-service.pid",):
|
|
pf = LOG / name
|
|
if pf.is_file():
|
|
try:
|
|
kill_pid(int(pf.read_text(encoding="ascii").strip()))
|
|
except ValueError:
|
|
pass
|
|
|
|
for pid in pids_on_port(8001):
|
|
print(f" free 8001 pid={pid}")
|
|
kill_pid(pid)
|
|
time.sleep(2)
|
|
|
|
env = os.environ.copy()
|
|
env["WEB_BASE"] = "http://127.0.0.1:5173"
|
|
env["PLATFORM_BASE"] = "http://127.0.0.1:8888"
|
|
env["GATEWAY_BASE"] = "http://127.0.0.1:8180"
|
|
env["GENERATE_LOG_DIR"] = str(LOG / "generate")
|
|
env["FIDELITY_SHOT_DIR"] = str(ROOT / ".runtime" / "fidelity_shots")
|
|
|
|
stamp = time.strftime("%H%M%S")
|
|
out_path = LOG / f"ai-service.{stamp}.out.log"
|
|
err_path = LOG / f"ai-service.{stamp}.err.log"
|
|
out_f = out_path.open("w", encoding="utf-8")
|
|
err_f = err_path.open("w", encoding="utf-8")
|
|
# also point stable names via copies later; use unique to avoid locks
|
|
(LOG / "ai-service.out.log.path").write_text(str(out_path), encoding="utf-8")
|
|
|
|
flags = getattr(subprocess, "CREATE_NO_WINDOW", 0)
|
|
p = subprocess.Popen(
|
|
[
|
|
sys.executable,
|
|
"-m",
|
|
"uvicorn",
|
|
"app:app",
|
|
"--host",
|
|
"127.0.0.1",
|
|
"--port",
|
|
"8001",
|
|
"--reload",
|
|
],
|
|
cwd=str(ROOT / "ai-service"),
|
|
env=env,
|
|
stdout=out_f,
|
|
stderr=err_f,
|
|
creationflags=flags,
|
|
)
|
|
(LOG / "ai-service.pid").write_text(str(p.pid), encoding="ascii")
|
|
print(f"started ai-service pid={p.pid}")
|
|
print(f" logs: {out_path.name} / {err_path.name}")
|
|
|
|
for i in range(45):
|
|
time.sleep(1)
|
|
try:
|
|
with urllib.request.urlopen("http://127.0.0.1:8001/docs", timeout=2) as r:
|
|
if r.status == 200:
|
|
print("OK AI http://127.0.0.1:8001")
|
|
return
|
|
except Exception as e:
|
|
if i % 5 == 4:
|
|
print(f" waiting... ({type(e).__name__})")
|
|
# show err log snippet
|
|
try:
|
|
print(err_path.read_text(encoding="utf-8", errors="replace")[-400:])
|
|
except Exception:
|
|
pass
|
|
raise SystemExit("AI failed to become ready on :8001")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|