feat(host-agent): add optional Appium/Runtime supervisor
Tests / Test failed: 2, passed: 691

Adds an opt-in dependency supervisor inside the Host Agent that probes,
spawns, and restarts the two local processes the macOS single-machine
real-device workflow depends on: the Appium server (gates Driver.connect())
and the local Runtime API (local inspection). Default-off; gated by
HOST_AGENT_DEPENDENCY_SUPERVISOR_ENABLED plus per-dependency *_SUPERVISED
flags.

Mitigates the live-incident failure mode where forgetting to start Appium
silently keeps devices offline and tasks queued forever with no error
surfaced in Host Agent logs.

Behavior (per openspec change):
- Adopt-don't-fight: probe (TCP + dependency-specific HTTP health check)
  before spawn. Healthy listener → adopted (never killed/restarted).
  Unhealthy listener → port-conflict error, skip. No listener → spawn.
- Only supervisor-spawned processes are restarted on crash, with capped
  exponential backoff (1s/2s/4s/8s, capped at 30s) and a per-process-lifetime
  attempt ceiling (HOST_AGENT_DEPENDENCY_RESTART_MAX_ATTEMPTS, default 5).
- Spawn failures (e.g. missing executable) logged distinctly from crashes.
- Graceful stop terminates only spawned children; adopted processes untouched.
- Supervisor starts before the heartbeat loop's first connect_devices() pass
  and stops alongside existing heartbeat/console teardown.

Validation: ruff check + format clean, compileall clean, openspec validate
--strict valid. Non-integration suite 503 passed / 44 deselected / 2 failed
(both failures pre-existing from unrelated 03c7c30 LLM_PROVIDER_ENC_KEY;
verified by stashing this change). macOS real-device manual verification
(task 6.4) deferred to a macOS host.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-07-14 09:28:57 +08:00
co-authored by Claude Opus 4.6
parent 03c7c30067
commit 75879c8a52
12 changed files with 1475 additions and 0 deletions
+55
View File
@@ -428,6 +428,61 @@ http://127.0.0.1:8765
session TTL、历史记录条数上限等)参见 `docs/CLOUD_DEPLOYMENT.md`;生产/远程场景下
应优先使用 SSH 端口转发访问该 Console,而不是直接把它暴露到非回环地址。
### 可选:由 Host Agent 托管 Appium 和 Runtime API
默认情况下 Host Agent **不会**自动启动 Appium 或本地 Runtime API:必须按
§6 在独立 Terminal 中保持 `appium --address 127.0.0.1 --port 4723` 运行,按
§8 在另一个 Terminal 中启动 Runtime API。忘记其中任意一个,Host Agent 不会报错,
heartbeat 仍会成功,但设备会静默保持 `offline`、所有任务卡在 `queued`
`host-agent-dependency-supervisor` 是一个可选模式,让 Host Agent 自己把这两个
外部进程作为子进程托管,覆盖单机真机工作流。它默认关闭,需要显式 opt-in:
```bash
export HOST_AGENT_DEPENDENCY_SUPERVISOR_ENABLED="true"
# 任选其一或两者都开。两者默认 false。
export HOST_AGENT_APPIUM_SUPERVISED="true"
export HOST_AGENT_RUNTIME_SUPERVISED="true"
# 可覆盖默认地址/端口(默认值与 §6/§8 手动流程一致):
# export HOST_AGENT_APPIUM_HOST="127.0.0.1"
# export HOST_AGENT_APPIUM_PORT="4723"
# export HOST_AGENT_RUNTIME_HOST="127.0.0.1"
# export HOST_AGENT_RUNTIME_PORT="8000"
# 单次 Host Agent 进程生命周期内允许的最大重启次数,默认 5。
# export HOST_AGENT_DEPENDENCY_RESTART_MAX_ATTEMPTS="5"
uv run --package device-host-agent device-host-agent
```
启用后的行为(详见 `openspec/changes/host-agent-dependency-supervisor/`):
- **启动顺序**:Host Agent 在第一次 `connect_devices()` 之前,先按上面选中的
依赖项依次做"先探测后启动"。这样一旦开启,Appium 不再需要单独的 Terminal。
- **Adopt-don't-fight**:探测 `(host, port)` 时若已经有进程在监听并通过健康检查
(Appium `GET /status` 返回 200 JSON,Runtime `GET /devices` 返回 200 JSON),
Host Agent 会以 *adopted* 方式记录日志,**不会**再 spawn 一个重复进程,也不会
在退出/崩溃时杀掉或重启它。如果端口被占但健康检查失败,记一条 port-conflict
错误并跳过该依赖,不抢端口、不静默继续。
- **崩溃重启**:只有 Host Agent 自己 spawn 出来的子进程才会被监控。子进程意外
退出时,按指数退避(1s、2s、4s、8s,封顶 30s)重启;当某个依赖在本进程生命
周期内累计达到 `HOST_AGENT_DEPENDENCY_RESTART_MAX_ATTEMPTS` 次重启后,停止
再次尝试直到 Host Agent 重启。被 adopt 的进程永远不会被 Host Agent 重启或杀死。
- **spawn 失败 ≠ crash**:如果 `appium` 可执行文件不在 `PATH` 上,启动会以
"dependency-supervisor: appium spawn failed — executable not found" 形式记一条
依赖主管特有的错误,与正常 crash 区分开。请确认按 §4.3 安装好 `appium`
XCUITest/UiAutomator2 driver。
- **退出时**:Host Agent 在自身 graceful shutdown 阶段只会 `terminate` 它自己
spawn 的子进程;adopted 进程保留不动。
- **不影响 Docker/Compose**:本模式只针对 macOS 单机真机工作流;
`compose.yaml` / `compose.deploy.yaml` 完全不受影响。
如果偏好保持对 Appium 终端日志的完全控制、或者已经在用其他进程管理工具
(launchd、systemd、tmux 等)托管 Appium,可以继续使用 §6/§8 的手动流程,
不开启本模式即可。
## 10. 多设备与端口
同时连接多台 iPhone 时,每台设备至少需要: