Files
creator-hub/docs/architecture/gateway-linux-runtime-plan.md
T

34 KiB
Raw Blame History

Gateway Linux Xvfb:规划、设计与验收

状态:设计草案,尚未实现、尚未通过运行验收。现状核对基线:main@977e541。 已确认范围:仅编写文档;保留 Docker,新增 Linux 物理机通过 Xvfb 虚拟屏幕启动浏览器。Linux 真实桌面、Windows/macOS 不在本次范围。XFVBXvfb 理解。 本文补充 plan01 的环境运行能力,不替代平台业务验收;现有部署步骤仍以 deployment 为准。下文配置、接口增量和时限均是待实现设计,不是当前可用功能。

1. 目标与完成标准

同一套 Python gateway 能管理 Docker 浏览器和 Linux 本机浏览器;本机浏览器仅通过 Xvfb 运行,不依赖显示器或图形登录会话。使用者仍从环境页面创建、启动、停止和回收,不能靠管理员手工启动 Chrome 后填写 CDP 地址冒充完成。

交付分为两个独立结论:

  • 文档完成:范围、现状差距、设计选择、接口影响、实施顺序、逐项验收步骤与失败判定完整;相对链接有效,未把目标描述成现有能力。
  • 功能完成(后续开发)Docker 回归通过,Linux 本机 Xvfb 完成创建到回收的真实闭环;人工登录、会话保存、并发与故障恢复均有证据;业务接口复用通过,不以 Mock 或健康接口代替浏览器与平台证据。

首轮验收基线为 Linux x86_64、Python 3.12+、可运行受控 Chromium 的发行版;测试记录必须填写发行版、内核、systemd、X server 和浏览器精确版本。ARM、原生 Wayland 启动、跨宿主机 Profile 搬迁不在本轮。

部署支持一个控制面中 Docker 环境和本机 Xvfb 环境并存;同一个 Linux 本机 gateway 下多个 Xvfb 环境可同时运行。单个 gateway 部署实例选择一种运行后端,不在同一进程内混管 Docker 和宿主机进程。

2. 当前能力与缺口

核对位置 当前实现 本次目标的缺口
cmd/docker_gateway/gateway.pyGatewayrun 生命周期围绕 DockerClient、容器标签和网络代际;入口构造 DockerClient 没有本机浏览器的创建、启停、回收、进程归属管理
同文件 external_cdp / BROWSER_CDP_URL 指定一个外部浏览器地址与 alias;列表返回 external;平台读取/动作可连接该浏览器 是接入已有浏览器,不负责启动;不能作为托管本机环境的实现,也不能用固定 runtime ID 证明新进程身份
docker/browser-wrapper/docker-entrypoint.sh 容器内启动固定 :99 Xvfb、x11vnc、CDP 转发,再启动 Chromium 固定显示号仅在容器隔离下适用;不能原样搬到多环境宿主机;现有入口不等于本机服务
cmd/control-plane/hub.gointernal/hub 创建参数、版本管理、运行识别、租约与清理包含镜像/容器/网络假设 需要明确本机运行信息,不能用假镜像、假 Docker network ID 填字段
cmd/docker_gateway/douyin.pyxiaohongshu.py 浏览器动作通过受控 CDP 连接执行,含账号与运行代际核验 应复用业务逻辑,只替换受控浏览器定位与生命周期,不复制平台连接器

特别说明:现有 external_cdp 列表的 proxy_ready=True 并不能证明本机启动或代理就绪;/healthz 可用也不能证明浏览器存在。

3. 方案选择

方案 优点 缺点 结论
只使用外部 CDP 接入 代码少,适合临时诊断 不拥有生命周期,无法保证回收与会话独占 不满足需求
每个 gateway 选择 Docker 或本机后端;本机仅使用 Xvfb 部署边界明确,可复用现有业务与控制面;本机不依赖 Docker 需调整生命周期契约与本机进程管理 推荐,本文采用
一个 gateway 进程同时管理容器和本机进程 注册入口少 同进程权限、依赖、故障边界混杂,没有当前必要性 不采用

不增加插件框架、调度集群、消息队列或另一套 HTTP 服务。用现有 Python HTTP 服务承载路由;内部按启动配置选择两个明确的执行实现,仅提取真正共享的生命周期操作与浏览器地址解析。

3.1 成熟模式与采用边界

  • Playwright 的 headed Linux 测试使用 Xvfb:虚拟屏幕承载正常有界面浏览器,不等于 headless;不自动获得可供人操作的远程桌面。
  • Chromium 用独立 user-data-dir 保存 Profile;同一个目录不能被多个浏览器实例同时使用,不能拿用户日常 Chrome 默认目录作为托管 Profile。
  • Xvfb 提供 X server;以实际 X client 连接确认就绪,而不是只看进程、socket 文件或固定等待。浏览器的 DISPLAY 与必要授权由本环境 Xvfb 启动流程提供,不继承宿主机桌面会话。
  • systemd 的服务/cgroup 用于托管本机进程树和重启后的归属核验;不以 PID 文件或进程名匹配作为终止依据。
  • 仅借鉴公开文档中的运行模式,不复制上游代码。采用的资料链接与许可证边界见第 10 节。

4. 运行与配置设计

控制面(Go,环境/账号/策略/运行记录)
  ├─ Docker gatewayPython,现有部署) → 容器 → Xvfb + 浏览器
  └─ 本机 gateway(同一 Python 服务代码,Linux 用户服务)
       ├─ 环境 A:专属进程组/cgroup + Xvfb + 浏览器 + 人工操作入口
       └─ 环境 B:专属进程组/cgroup + Xvfb + 浏览器 + 人工操作入口

Docker gateway 保持现有部署及 socket 归属;本机 gateway 不要求 Docker socket、镜像或 Docker 网络存在。宿主机无 Docker daemon 时,本机模式也必须完整启动。控制面通过注册地址访问 gateway;部署需验证容器到宿主机的实际连通地址,不能把控制面容器内的 127.0.0.1 当成宿主机。

4.1 拟新增配置

所有配置先校验再创建目录、显示服务或浏览器;未知模式、缺少必要字段直接报错,不尝试切换另一模式。

配置/字段 所属层 规则
BROWSER_RUNTIME=docker|native gateway 启动配置 显式选择;Docker 现有部署在实现时写明 docker
本机浏览器版本 → 绝对可执行文件路径 本机 gateway 配置 有限版本表;文件存在、可执行、版本可探测;API 不能指定任意命令或 shell 文本
本机 Profile 根目录、运行状态目录 本机 gateway 配置 绝对路径、目录可写;Profile 长期保存,临时状态与其分离;禁止路径越界
Xvfb 屏幕参数 本机 gateway 配置 初始固定为 1920x1080x24;确有不同尺寸需求再扩展环境参数

环境选择 gateway 后由 gateway 能力决定运行后端,不允许请求声称 native 却发给 Docker gateway。本机版本来自部署者明确安装的受控浏览器,版本与二进制校验值进入验收记录;不因启动失败自动下载替代浏览器,不假设普通 Chrome 能等价支持现有指纹参数。

本机显示固定使用 Xvfb,不新增显示模式选择参数。DISPLAY 与必要的 Xauthority 由 gateway 为每个实例生成、传递和清理,不读取宿主机图形会话作为替代。

4.2 Xvfb

  • 每个运行实例独立 Xvfb,动态分配显示号;采用 X server 支持的分配机制并验证目标发行版能力,不扫描出一个空闲号后无保护地占用。
  • 启动顺序:运行锁和 Profile 锁 → 持久保存启动归属记录 → 创建环境 unit → Xvfb → X client 连接探测 → 按平台出口配置准备请求中转 → 浏览器 → CDP 与目标页探测 → 人工操作入口探测 → 持久保存启动完成记录 → running。
  • 不复用容器入口中的固定 :99,不删除不属于当前实例的 /tmp/.X*-lock 或 X11 socket。
  • Xvfb 被杀、显示断开时停止本环境浏览器与操作入口,标记失败并保留 Profile;不得切换 headless,也不得自动重放业务发送。
  • Xvfb 本身不是远程桌面。复用项目现有浏览器操作链路,提供该显示实例专属的 x11vnc/RFB 入口供人工登录、验证码和确认;只有画面可见而不能输入不算通过。不新增第二套远程桌面产品;需在实施第一阶段核对现有入口能否无损接入本机运行地址。

4.3 本机进程归属与重启

每个运行实例使用独立的 systemd 用户 transient service/cgroup;由环境 runner 启动并监督本环境的 Xvfb、浏览器和 RFB 子进程,设 KillMode=control-group,禁止失败自动重启浏览器。主 gateway 重启与环境子服务分离,避免主服务退出就误杀仍需核验的环境。

创建 unit 前必须先持久保存启动归属记录,包含 alias、binding version、随机生成的 runtime ID、唯一 unit 名、Profile 路径、operation ID 与 starting 阶段;记录保存失败不得创建 unit。unit 必须携带可与记录核对的运行身份。随后将本次分配的 Xvfb 显示号、CDP 端点、中转监听地址与启动时间补入记录;所有就绪检查通过并持久保存启动完成记录后,才报告 running、允许业务动作和订阅。记录更新必须原子替换并确保落盘,不能以仅写入进程内存作为完成依据。

PID 仅用于诊断;重启时同时核对 unit 的运行身份、受控路径、运行记录和实际 CDP。Profile 独占锁在环境存活期间由环境 runner 持有,不因主 gateway 退出而释放;交接期间不得出现可被另一实例抢占的窗口。

重启恢复分支按以下顺序处理,恢复检查完成前不得报告 running 或接收业务动作:

  1. 元数据、unit 或 Profile 所有权无法确认或不一致 → 进入 unknown,阻止同 Profile 再启动,不认领、不终止可疑进程;输出可定位原因,人工核验后显式回收。发现缺少记录的疑似托管 unit 也按此处理,不忽略残留。
  2. 归属记录仍为 starting,尚未持久保存启动完成 → 不续跑启动、不自动重启;核对归属后,仅清理本次 unit 与临时资源,保留 Profile。即使浏览器已能连接,也不视为启动完成。确认资源已释放后记录 failed;清理结果无法确认则为 unknown。记录存在但 unit 尚未创建时同样收敛为失败,不创建新 unit。
  3. 已完成启动的 unit 已退出 → 记录停止或失败,确认子进程已回收后释放锁与租约。
  4. 已完成启动且归属相符的 unit 仍在运行 → 按第 5.4 节恢复请求中转,检查显示、CDP、所选出口及人工操作入口;人工入口须验证画面与输入能力,与首次启动标准一致。全部通过后才恢复运行报告,并在账号身份核验通过后恢复事件订阅,不新建浏览器、不重放业务动作。
  5. 上述存活实例的任一就绪检查失败 → 不恢复业务与订阅,记录具体失败原因;归属已确认时停止本次运行并保留 Profile,清理完成为 failed,清理结果无法确认则为 unknown。不得以人工入口不可用、出口配置暂不可取等理由跳过检查。

采用 systemctl --user 管理现有用户服务,不引入 Python systemd 库。无用户服务管理器时启动配置失败,不回退到无人管理的后台进程。无图形登录的服务器重启后运行需由部署者配置用户服务驻留(linger);浏览器只依赖本环境 Xvfb,不要求已有桌面会话。

5. 生命周期、数据与接口

5.1 共享语义

动作 目标行为
create 保存已校验的环境配置并准备持久 Profile,返回停止态;不提前启动浏览器
start 按 alias 串行;获取跨进程 Profile 独占锁;分配新 runtime ID;按第 4.3 节先保存归属记录,再准备显示、请求中转与浏览器并逐项验证。相同配置已就绪则返回当前实例,不再启动第二个
stop 核对运行归属;先停接收新业务动作、停止订阅,再关闭浏览器,随后 RFB/Xvfb;保留 Profile
recycle 只回收本次受控运行资源与临时记录;保留环境、绑定和 Profile,供以后重新启动
upgrade 停止旧实例并保留 Profile;使用已安装且启用的目标浏览器版本重新启动;不自动降级或回滚;失败不声称升级成功
rebind 延续停止且无执行中任务的要求;更新出口绑定后,下次启动应用;不在运行中切代理

stopped → starting → running → stopping → stopped 为正常路径;确认失败进入 failed,结果无法确认进入 unknown。这些是设计状态,实施时需在控制面、gateway 和页面一致表达,不把“进程存在”当成 running。对外动作结果不明时先查询核验,不自动重发业务写操作。

启动总时限初始定为 60 秒;停止给予浏览器 15 秒优雅退出,之后终止该 unit 的剩余进程树,总时限 30 秒。超时返回明确错误或 unknown,必须保留原始失败步骤和清理结果。强制退出需提示会话最后一次写入可能丢失。启动中途失败按创建顺序逆向清理,仅删除本次临时资源,绝不删除 Profile。

5.2 Profile 与并发

Profile 固定绑定环境与宿主机:<profile_root>/<alias>,不同 alias 不共享目录。使用操作系统文件锁与 Chromium 自有锁共同防止重复启动;只检查目录存在或 Python 线程锁不够。两个 gateway 进程争抢同一 Profile 必须只有一个成功。

停止、回收、主 gateway 重启均不删除 Profile;升级也不搬迁 Profile。版本不兼容时明确失败,不自动清空登录数据。登录保存仅指保留平台允许持久保存的会话,不承诺平台不会撤销或要求重新登录。切换 gateway/宿主机视为新部署,禁止把跨机复制 Profile 包含在本轮。

5.3 契约增量(待实现评审)

保持现有 /api/browsers/v1/browsers 的领域入口及 Docker 动作含义;本机增加条件字段,不把本机浏览器伪装成 Docker 容器。以下是拟定契约,不是可直接调用的现有接口:

位置 增量与约束
gateway 能力查询(拟 GET /v1/capabilities 返回 runtime_backend、可用浏览器版本、人工操作能力;native 显示方式固定为 Xvfb;缺失或查询失败显示不可用,不猜测能力
gateway 注册信息 保存/展示后端能力;请求与当前能力不符拒绝;不依赖名称中是否带 docker 判断
环境创建 Docker 继续使用 image_versionnative 使用 browser_version,不接受显示模式选择字段;两类版本字段互斥,错误组合返回 400
native 启动载荷 受校验 alias、binding version、浏览器版本、指纹与出口;不接收任意 executable、Profile 路径、DISPLAY、shell 或 CDP URL
运行记录/列表 明确后端、runtime ID、就绪状态与失败原因;native 不要求容器 ID 格式,也不伪造 network_id
代际校验 共享使用 alias、binding version、runtime IDDocker 额外保留真实 network ID 校验;native 核对受控 unit 和进程归属
upgrade 保留 {version} 动作形态,根据已确定后端查镜像版本或本机浏览器版本,不跨后端升级
页面 按 gateway 能力展示对应版本;本机显示固定标注 Xvfb,不提供显示模式选择;错误、禁用原因可见,显式启停回收仍是独立动作

HTTP 设计:输入错误 400;不存在的环境 404;运行归属、Profile 占用或版本冲突 409;显示/浏览器依赖不可用 503;下游执行失败 502;启动或清理超时 504。错误体保留现有可读错误信息并增加稳定错误码和 operation ID;不在错误体输出秘密。Docker 已有状态码不在本次顺带重写。具体字段、Go/Python 解析器、数据库约束和前端类型必须在同一实施变更中更新并测试。

开发阶段允许重建开发数据库,不做旧运行数据回填、双写或假字段兼容。已有 Docker 对外语义继续维护,不等于保留已经废弃的内部假设。external_cdp 不接入托管环境创建流程;其是否仍有独立诊断用途需检查调用方,废弃时直接删除,不成为启动失败的回退路径。

5.4 代理、平台动作和监听

代理及其出口配置、凭据和环境绑定由平台管理;gateway 只按平台下发的配置中转请求,不创建、启停或自行选择上游代理。复用现有浏览器侧无需凭据的本地转发器;本机浏览器使用本机可达的转发地址,不能复用只在 Docker 网络内可达的 gateway 地址。出口凭据不进入浏览器命令行、配置文件或日志。明确直连与绑定代理是不同选择:绑定代理不可用必须失败,不能改为直连。

现有中转器运行于 gateway 进程内,主进程退出后不能假定中转仍可用。恢复时由平台依据 alias、binding version、runtime ID 核对当前运行及出口绑定,并重新下发所需中转配置和凭据;gateway 不从本地运行记录恢复秘密,也不自行更换出口。对仍存活的浏览器,须重建其原中转监听地址和端口,并通过实际浏览器请求确认所选出口可用后才能报告 running。平台无法提供配置、绑定不符、原端口被其他服务占用或出口验证失败时,执行第 4.3 节失败分支,不切直连、不换端口冒充恢复成功。重复下发同一运行配置应幂等,旧运行配置须拒绝;该恢复交互的具体接口纳入 P0 契约说明。

本机模式本轮不新增宿主机防火墙或网络隔离,不能宣称与现有 Docker 隔离等价。验收需证明实际浏览器请求经过选定代理、失败可见;不宣称已实现操作系统级防泄漏。

抖音/小红书继续使用现有页面内业务动作与身份校验;runtime 改变时旧订阅停止,新实例重新核验身份后建立订阅。人工发送仍逐次确认,自动响应仍由策略与 UID 冷却决定。平台通知保持事件监听;进程健康探测不是业务事件轮询的替代方案。断线期间平台若无法补齐事件必须显示缺口,不承诺无证据的无丢失恢复。

6. 日志与失败可见性

关键节点均记录开始、完成或失败:配置校验、Profile 加锁、启动归属记录落盘、unit 创建、显示就绪、请求中转就绪、浏览器启动、CDP 就绪、人工入口就绪、启动完成记录落盘、恢复配置核对、中转重建、未完成启动清理、订阅恢复、停止、强杀与回收。

稳定字段:serviceoperation_idaliasruntime_backendbinding_versionruntime_idstageduration_msoutcomeerror_code。进程退出补充 unit、退出码/信号;异常保留经过脱敏且有长度上限的 stderr。Profile 仅记录环境内相对路径;不输出 Cookie、密码、代理凭据、Xauthority 内容或完整 CDP WebSocket 秘密地址。

/healthz 只证明 gateway HTTP 进程存活;能力可用、环境 running、平台账号可用分别验证。失败清理也失败时,两条事实都要保留,不能只留下“启动失败”而隐藏残留进程。

7. 分阶段实施计划

每阶段先写会失败的最小回归测试,再实现;前一阶段具备真实端到端证据后再扩展。开发前新建功能分支,本文提交不启动重构。

阶段 交付物 退出条件
P0 契约与能力核对 最小接口/schema 变更说明;锁定本机浏览器;证明 systemd 用户服务、Xvfb 分配、现有人工操作链路能使用 无假容器/网络字段;本机 Xvfb 方案实际可行;依赖来源与版本明确
P1 本机 Xvfb 最小闭环 一条从页面 create/start/stop/recycle 到 Xvfb 浏览器的链路;独立 Profile;人工操作入口;显示失败可见 A01A08、A10、A14 通过;Docker 最小回归通过
P2 多环境与故障处理 多个 Xvfb 实例并存;显示、端口冲突与进程故障清理 A09、A11A13 通过,无显示号或 Profile 冲突
P3 恢复与业务回归 重启调和(含未完成启动清理)、旧代际保护、请求中转恢复、平台读取与事件连接、完整日志 A15 的重启会话保存及全部恢复分项通过;第 8 节全部必测用例与自动检查通过;真实平台结论与范围明确

优先复用 gateway.py、现有 DockerClient/代理/CDP 连接器;新增本机生命周期模块及测试。控制面、internal/hub、环境页面只增加实际需要的后端能力字段,不另建产品管理框架。实现时核对精确文件职责,不按本计划盲目拆文件。

8. 验收方案

8.1 场地和记录要求

准备一台没有图形登录/物理显示器的 Linux 主机验证本机 Xvfb;另保留现有 Docker 部署作回归。资源受限时,可用独立无显示会话的 Linux VM 验证,但不能用容器内已有 Xvfb 代替本机验收。无需准备真实桌面测试环境。

准备已锁定浏览器版本、专用测试 Profile、测试账号、可控代理、可发送测试事件的对端账号。真实发送仅用测试对象并遵守人工确认/自动策略。故障注入仅针对本次受控 unit,不使用 pkill chrome 等全局命令。

实施 PR 必须补齐可执行命令清单:安装依赖、创建用户服务、设置 gateway 配置、注册能力、调用生命周期接口、定位日志及故障注入。本文不提供尚未实现的虚假启动脚本。下面步骤通过现有页面动作描述,新增字段/操作入口待实现后必须可由测试人员直接执行。

每例记录:用例 ID、代码 commit、机器及依赖版本、运行后端、开始结束时间、输入摘要、operation/runtime ID、预期与实际、脱敏日志/截图路径、通过/失败/阻塞。没有证据一律不填“通过”。

8.2 必测用例

ID 执行步骤 通过标准
A01 无 Docker 本机启动 在无 Docker daemon/socket 的主机配置 native,启动 gateway;查询健康与能力 HTTP 可用,能力明确 native;不尝试连接 Docker;能继续创建环境
A02 参数校验 分别提交未知后端、版本不存在、非法显示模式字段、越界路径/非法 alias、混用两类版本字段 分别明确拒绝;没有新增 unit、浏览器或遗留临时文件;Profile 不被删除
A03 创建不启动 创建一个 native 环境;查看进程与页面状态 环境停止态;Profile 归属正确,无提前启动的浏览器/Xvfb
A04 显示依赖校验 分别移除 Xvfb 可执行文件、使 X client 无法连接;再设置继承 DISPLAY 为其他显示服务地址并启动 依赖失败明确报错且清理本次资源,不切换 headless;正常启动只使用自建 Xvfb,不连接继承的显示地址
A05 停止/回收后会话保存(P1 人工登录测试账号,记录身份;依次 stop/start、recycle/startgateway 重启恢复另见 A15P3 Profile 保留;平台未主动撤销时身份一致;若平台要求再登录则如实记录原因,不能用该情况掩盖 Profile 丢失
A06 无屏启动 无桌面主机清空继承 DISPLAY,启动 native 环境并使用人工入口访问、点击和输入 新建专属 Xvfb;浏览器 headed;远程画面和输入均正常;不需要物理屏幕
A07 人工登录 Xvfb 人工入口完成平台登录,遇到验证码由人处理;读取自身身份 无自动注入密码/验证码;身份匹配;无法完成登录记阻塞,不以静态截图代替
A08 停止与回收 对本机 Xvfb 执行 stop 两次、start、recycle 两次;观察 unit/端口/显示/目录 动作幂等;受控进程树与监听端口已释放;Profile 保留;不关闭其他显示服务
A09 多环境 同一 native gateway 同时启动 Xvfb 环境 A、B、C;分别改变页面,再停止 B 三个 Profile、runtime、显示号独立;B 停止不影响 A/C;Docker 环境同时正常
A10 同 Profile 争用 并发发送同 alias start;再让另一 gateway 实例争抢同一 Profile 第一次最多一个浏览器;重复同请求返回已有实例或明确冲突;跨进程冲突 409;无 Profile 损坏
A11 显示与端口冲突 占用候选显示号;制造 CDP/RFB 端口占用;使 X client 连接失败 仅在正常分配阶段另选未占用资源或明确失败;不连接别人的服务;失败有阶段与清理证据
A12 子进程故障 分别终止受控 Xvfb、浏览器、人工操作服务;再次执行健康/状态查询 浏览器或显示失效不得仍报 running;必需操作入口失效可见;清理仅限本环境;没有自动重发动作
A13 启动/停止超时 让受控浏览器在启动阶段无响应、在停止阶段不退出 60 秒启动上限后失败并清理;停止 30 秒内终止受控进程树或标记 unknown;原始失败和清理结果可查
A14 不误杀 同用户另启非托管测试进程和独立 Xvfb 浏览器;启动/停止/回收托管环境;模拟记录 PID 被复用 非托管进程、独立显示服务与其他环境不受影响;所有权不符拒绝终止并报告原因
A15 gateway 重启与崩溃恢复(P3 按下方 A15 分项分别测试正常重启、运行中崩溃、启动中断、请求中转恢复、人工入口失效和归属异常 每个分项分别留证;匹配且就绪的已完成实例才恢复;未完成启动只清理,不新开浏览器;Profile 保留,残留资源和失败原因可查
A16 主机重启 保留 Profile,重启无图形登录主机,恢复用户服务并启动环境 不把旧 runtime/PID 当新实例;旧实例已退出;经显式 start 新建 Xvfb 运行实例,无需桌面会话
A17 代理与断线 本机 Xvfb 分别选直连、选测试代理;通过浏览器请求检查出口;再停代理 直连按选择工作;代理模式流量到达所选出口;失效可见且无自动直连;日志/参数无凭据
A18 旧代际请求 重启生成新 runtime;对新环境提交旧 stop/业务动作/订阅请求 409 或对应明确代际冲突;新实例未被操作,旧监听不继续发送
A19 版本升级 用已安装目标版本升级;再选不存在/不兼容版本;检查 Profile 和恢复操作 成功使用目标版本且保留 Profile;不存在版本在启动前拒绝;不兼容如实失败,无清空或降级
A20 平台链路 本机 Xvfb 先验证抖音自身身份和读取;由测试对端产生互动事件;按 plan01 验证确认/策略;随后同样核对小红书 真实事件来自当前账号/实例,无旧订阅重复执行;写前核对身份,人工逐次确认,自动遵守策略;平台缺口明确列为阻塞
A21 Docker 回归 原部署重复 create/start/stop/recycle/upgrade、出口故障、租约恢复和人工操作 原 Docker 行为不变;native 依赖不成为 Docker 启动条件;没有假 native 数据进入 Docker 解析
A22 页面与诊断 两类 gateway 切换创建环境,查看失败详情、禁用项、运行模式;按 operation ID 查完整启动失败链 只展示当前能力允许的字段;失败可定位;不展示秘密;服务健康与浏览器状态不混淆

A15 必须分别记录以下结果,不得只验证运行中的直连环境:

  • 已完成实例与会话:人工登录后分别正常重启、强制终止并重启主 gateway;原 runtime 不变、不新开浏览器,Profile 保留。平台未撤销会话时身份一致;平台要求重新登录时记录原因,不能掩盖 Profile 丢失。
  • 启动中断:分别在归属记录落盘前后、unit 创建前后、启动完成记录落盘前后终止 gateway。归属记录未落盘不得已有 unit;完成记录未落盘的本次资源仅清理、不续跑;完成记录已落盘的实例按完整就绪检查恢复。每次均核对进程、端口、显示、锁与 Profile,不能留下无法解释的残留,也不能重复启动。
  • 归属与清理异常:分别测试 unit 已退出、记录缺失或不符、Profile 所有权不符、清理失败;已退出如实停止,无法确认归属或清理结果时进入 unknown,阻止同 Profile 再启动,不误杀其他进程。
  • 请求中转恢复:使用平台绑定的测试代理,在浏览器运行时终止 gateway;重启后由平台重新下发匹配配置,验证原中转地址恢复且实际浏览器出口正确。另测配置不可取、绑定不符、原端口被占用、上游不可用;均不得恢复 running 或改为直连。重复下发不创建重复中转,旧运行配置明确拒绝。
  • 人工入口失效:保持 unit、显示、CDP 和出口可用,仅使 RFB 入口不可见或无法输入,再重启 gateway;不得恢复 running 或事件订阅,按失败分支清理并保留 Profile。

A20 的真实平台验收按 plan01 顺序执行:先抖音,后小红书。平台自身能力未验证不得阻挡对“本机运行层”作单独结论,但不得将运行层通过写成“两平台业务全部通过”。所有跳过项必须列出,不能默认视为通过。

8.3 自动化检查与门槛

实现必须保留最小可复现回归测试:模式校验、条件载荷、Profile 跨进程锁、超时清理、归属与旧代际拒绝、重启恢复、秘密脱敏。用真实进程/文件锁验证生命周期关键边界;Mock 只用于可控错误注入,不代替真机显示验收。

  • Pythonpython -m unittest discover -s cmd;覆盖率检查必须覆盖 native 生命周期与 gateway 集成,相关模块和整体单元测试覆盖率均不低于 65%。覆盖率工具加入开发依赖锁定文件,实施 PR 提供实际非交互命令及报告。
  • Gogo test ./...go vet ./...go build ./cmd/control-plane;涉及运行状态/并发,必须加 go test -race ./...
  • 前端:npm --prefix web ci、仓库实际非交互测试命令、npm --prefix web run build;新增能力选择、失败/禁用状态有交互测试。
  • Dockerdocker compose config --quiet,构建、启动、健康检查及 A21;不得仅凭配置解析通过宣称运行通过。
  • 本机:Xvfb 安装/启动命令、用户 unit 配置、故障注入步骤和 A01–A22 证据一并交付。

文档任务本身不需要运行上述功能测试;当前没有 native 实现,运行旧测试也不能证明它存在。

9. 风险、排除项与交付判定

  • 显示归属:浏览器必须连接当前实例的 Xvfb,不能继承宿主机 DISPLAY 或误连其他显示服务;以连接探测与归属核验验证,不以进程存在代替。
  • 浏览器发行版差异CDP、指纹参数和 Profile 升级行为需用所选二进制验证;不承诺任意浏览器兼容。Chrome 136 起针对默认数据目录的远程调试参数受到额外限制,专用 Profile 是必要设计,仍需验证所选 Chromium 派生版本。
  • 同用户多显示会话:Chromium 官方资料提示多图形 session 可能存在 D-Bus 串扰;不同 Profile 不足以证明多个 Xvfb 实例并发可用。P0 必须实测 D-Bus、密钥环与登录持久性;若需要独立 session bus,优先验证系统已有 dbus-run-session,证据不足时阻塞,不提前承诺隔离已完成。A09 除窗口互不影响外,还必须核对各自账号身份与重启后的持久数据。
  • 远程人工操作:Xvfb 能启动不代表登录可完成;A06/A07 是必测,不允许缩减为 headless 截图。
  • 系统依赖systemd 用户服务与 Xvfb/x11vnc 为本机部署依赖;无此依赖不是“部分成功”,必须阻断并提示安装要求。
  • 业务结果不确定:gateway 崩溃后浏览器可能仍执行最后一次动作,恢复仅核验结果,不自动重放发送。
  • 不新增Linux 真实桌面支持、Windows/macOS 支持、跨机器 Profile 迁移、任意 CDP/命令服务、自动登录、平台风控规避、认证系统或本机网络隔离。

功能验收结论必须分别填写:Docker 回归、本机 Xvfb、抖音业务、小红书业务。任一核心生命周期/归属/Profile 测试失败,本机 Xvfb 支持不能标为完成。真实账号或机器条件缺失时写“阻塞及所需条件”,不能写“预计通过”。

10. 官方资料

下列为设计依据,不是本仓库已完成证明;引用运行约定,不复制实现代码。实际引入软件时登记所选版本、来源和许可证;Playwright 为 Apache-2.0Chromium 使用 BSD 风格及第三方许可证,X.Org 组件以各包许可清单为准,systemd 以其发行包许可清单为准。