"""Atomic JSON file I/O for cross-process health state sharing.
Used by the heartbeat subprocess (writer) and EndpointView (reader).
Health file schema is a plain dict: {"endpoints": {"host:port": {alive, last_seen,
providers, hardware, ts}}} — written by heartbeat_loop, read by EndpointView.
"""
import json
import os
import tempfile
from typing import Optional
def atomic_write_json(path: str, data: dict) -> None:
"""Write dict as JSON to path atomically via tempfile + os.replace.
Creates parent directories if missing. Uses os.replace for POSIX atomicity:
readers never see a partially-written file.
"""
parent = os.path.dirname(path) or "."
os.makedirs(parent, exist_ok=True)
fd, tmp = tempfile.mkstemp(dir=parent, prefix=".xpu_health_", suffix=".json")
try:
with os.fdopen(fd, "w") as f:
json.dump(data, f)
f.flush()
os.fsync(f.fileno())
os.replace(tmp, path)
except Exception:
if os.path.exists(tmp):
os.unlink(tmp)
raise
def read_health_file(path: str = "") -> Optional[dict]:
"""Read health state dict from disk. Returns None on any failure.
Tolerates: missing file, missing env var, corrupted JSON, permission errors.
Workers call this on every dispatch — must never raise.
"""
if not path:
path = os.environ.get("TTK_XPU_HEALTH_PATH", "")
if not path:
return None
try:
with open(path, "r") as f:
return json.load(f)
except (FileNotFoundError, json.JSONDecodeError, PermissionError, OSError):
return None