Skip to content

网关 PHY 预检

概述

在启动真实网关模式(mode=gateway)运行前,系统执行 PHY 预检流程,探测每个候选 UNET 节点的健康状态,仅选择满足条件的节点参与调度。

预检逻辑位于 orchestrator/gateway_preflight.py,由 runner.pyrun_demo() 启动时调用。

预检流程

对每个候选节点:

    ├── 1. adapter.connect(inst)       # 建立网关 TCP 连接

    ├── 2. adapter.probe(inst)         # 探测 agent 列表与服务

    ├── 3. adapter.check_phy(inst)     # 检查物理层状态
    │       └── 返回 {"ok": bool, "detail": str, ...}

    ├── 4. adapter.query_node_address(inst)  # 查询节点 UNet 地址
    │       └── 健康节点写入 inst.meta["unet_addr"]

    └── 5. adapter.close(inst)         # 关闭连接

数据结构

PreflightReport

每个节点的探测结果:

python
@dataclass
class PreflightReport:
    node_id: int           # 节点编号
    name: str              # 节点名称(如 "A")
    host: str              # 主机地址
    port: int              # 端口号
    healthy: bool          # 是否健康
    detail: Optional[str]  # 异常详情
    phy_info: Dict         # PHY 检查原始返回
    address: Optional[int] # UNet 地址(仅健康节点)

PreflightSelection

选择结果:

python
@dataclass
class PreflightSelection:
    required_count: int              # 场景要求的最少节点数
    preferred_node_ids: List[int]    # 优先选择的节点 ID 列表
    candidates: List[UnetInstance]   # 所有候选节点
    healthy: List[UnetInstance]      # 通过检查的健康节点
    selected: List[UnetInstance]     # 最终选中的节点
    reports: List[PreflightReport]   # 每个节点的详细报告

节点选择策略

  1. 优先列表优先:按 preferred_node_ids 顺序,从健康节点中挑选
  2. 补充剩余:如果优先列表不足,从其他健康节点中补充
  3. 截断到所需数量:最终选中列表长度 = min(len(healthy), required_count)

异常处理

GatewayPreflightError

当健康节点数量不足 required_count 时抛出:

GatewayPreflightError: Not enough healthy PHY nodes:
    required=3, healthy=1,
    failed=[node 2 (B): ConnectionError: ...; node 3 (C): PHY agent missing]

容错机制

  • 单节点 connect/probe/check_phy 异常不会中断整个预检流程
  • close 失败静默忽略(_safe_close
  • query_node_address 失败仅记录 warning,不影响节点健康判定

与 Runner 集成

python
# orchestrator/runner.py 中的调用路径
def run_demo(..., strict_gateway=True):
    if mode == "gateway":
        selection = run_phy_preflight(
            adapter=adapter,
            candidates=candidate_instances,
            required_count=len(traffic_flows),
            preferred_node_ids=[...],
        )
        # 使用 selection.selected 作为实际参与调度的节点

strict_gateway=True 时预检失败将直接终止运行;False 时降级为可用节点子集继续执行。