175 lines
19 KiB
Markdown
175 lines
19 KiB
Markdown
# 原生浏览器环境:评审后的实施计划
|
||
|
||
> 状态:实施 worktree 已按本计划完成 native gateway、控制面契约、runtime-use lease、前端和单机部署代码改造;自动检查与真实平台/代理/LAN 验收分开记录,缺少授权或真实资源时标为阻塞。
|
||
> 依据:[变更评审](native-browser-change-review.md)、[业务基线](plan01.md)。验收:[验证文档](native-browser-verification.md);记录:[单节点验证记录](evidence/native-browser-verification-2026-09-18.md)。
|
||
|
||
## 1. 完成定义
|
||
|
||
满足以下条件才算完成改造,而不是“可以启动 Chromium”就结束:
|
||
|
||
- 各 gateway 不访问 Docker socket,不创建浏览器容器、镜像层、卷或网络;每个 runtime 在本机运行 Xvfb 与指定版本浏览器。
|
||
- 本目标先通过现有控制面管理单台机器;账号、运行代次、代理、Profile 与实际节点一致,不自动跨机重建。多节点仅保留稳定契约字段,另立目标。
|
||
- 采集任务可按需启停;任务自建进程和临时文件在所有终态回收。清理失败真实可见并可重试。
|
||
- 持久登录、Profile、稳定指纹及账号身份在重启和普通浏览器升级后保持;二维码登录、采集结果及逐次确认的人工发送不退化(A02、A10;AC-E1)。
|
||
- gateway、控制面重启及监听重连不清除自动响应的事件去重、基线或 UID 冷却;旧事件不重放,迟到事件默认只记录、不自动补发(C02、D04;AC-A9、AC-B1)。
|
||
- HTTP、HTTPS、SOCKS4、SOCKS5 及协议支持的认证配置逐项验证实际浏览器出口、认证失败和网络失败,失败不得直连(A09、B03、D05;AC-E3)。
|
||
- 控制面本机的素材临时文件同样受执行归属和清理约束;旧任务不能覆盖新产物。
|
||
- 旧 Docker 浏览器路径彻底删除;构建/测试达标,局域网环境可供用户手工验收,资源对比有实际记录。
|
||
|
||
## 2. 保持简单的目标结构
|
||
|
||
```text
|
||
React → Go control-plane(账号/任务/绑定/业务结果/素材发布)
|
||
└─ native gateway G(单节点;保留后续节点登记契约)
|
||
├─ 预安装浏览器版本(所有任务共用只读二进制)
|
||
├─ 账号的持久 Profile
|
||
└─ runtime generation:Xvfb + 浏览器 + 临时目录
|
||
```
|
||
|
||
- 继续使用 Go 控制面、Python gateway、PostgreSQL 与现有 CDP/WebSocket。
|
||
- 用 Linux/systemd transient unit 管理每个运行实例;gateway 使用 Python 标准库调用明确的进程管理操作。固定的 runner 仅启动 Xvfb、浏览器和批准的桌面组件,不是可执行任意命令的接口。
|
||
- 一 runtime 一 Xvfb,按需启动,不设浏览器池、不预热空闲实例。
|
||
- 不为 Docker/原生模式保留可切换后端。实施分支可以暂时有未发布的中间步骤,但交付只保留原生路径。
|
||
- 先完成“单机账号登录 → 抖音采集 → 资源释放”最小完整流程,再扩展为多机与全部业务回归。
|
||
|
||
## 3. 必要数据和接口变化
|
||
|
||
以下为本实施 worktree 已采用的**单节点契约**;多节点字段保留稳定命名,但跨机调度与恢复不在本目标内。
|
||
|
||
| 概念 | 变更 | 约束 |
|
||
| --- | --- | --- |
|
||
| gateway | 保留节点登记、显示名称与 Endpoint;新增持久稳定节点身份/能力 | 仍有关联资源时不得把旧节点改指新机器;无自动迁移 |
|
||
| browser version | 删除镜像拉取/构建语义,改为预安装浏览器版本及可用状态 | 每台 gateway 核对实际版本、指纹参数与路径;缺失时明确报错 |
|
||
| environment | 保留稳定账号环境、指纹与绑定;版本字段去除 image 语义 | 环境定义不等于正在运行的浏览器,元数据创建不应提前占用进程 |
|
||
| runtime | 用节点身份 + environment + generation 代替 container/network ID | 状态、清理、事件和代理绑定均核对代次;不能只用 PID |
|
||
| profile | 原 Docker volume 改为 gateway 依据内部 ID 生成的持久目录 | 单 Profile 独占打开;任何任务请求都不能指定任意删除路径 |
|
||
| task use/lease | 复用现有任务与 lease 表/模式,增加 runtime 使用目的、所有权和期限 | source lease 不等于 runtime lease;长任务须续租,暂停等待不提前分配浏览器 |
|
||
| cleanup | 业务状态与 cleanup 状态分别记录,并保存资源 owner 与最后错误 | 成功且待清理不等于业务失败;不得借清理重试重复采集/发送 |
|
||
| material artifact | 每次执行独有临时目录与不可变产物路径,DB 按执行 token 发布引用 | 发布结果未知时查询事实后再删;清理不能删除已被正式引用的文件 |
|
||
| gateway create/delete | 保留显式创建、启动、停止、回收动作,替换 Docker 载荷 | 重复创建使用同一 generation;响应丢失时查询同代次,不能直接换 ID 重开 |
|
||
|
||
### 状态与错误语义
|
||
|
||
- 区分浏览器就绪与账号可执行:CDP/页面就绪后即可进入人工登录;未登录时显示待登录,而不是永久“正在启动”。只有代理和实际账号身份确认后才允许采集/写操作;身份不一致立即拒绝写操作。
|
||
- gateway 不可达、响应丢失、写入结果不确定时,记录未知/待核对,不自动重试平台写操作。
|
||
- 明确区分校验失败、Profile 占用/代次冲突、节点/依赖不可用与服务内部错误。P0 列出当前状态码及预期变化并批准;不在实现中悄悄改为 `200`。
|
||
- 删除已经不存在的同代次资源应可重复执行;针对旧代次的删除不得作用于新实例。
|
||
- 去除 `container_id`、Docker 网络及 image 字段会影响 API、UI 和测试。采用受控的破坏性开发切换,不增加兼容字段、双写或迁移回填。
|
||
- 数据重建不等于可以删除用户 Profile/素材。实际删除与重新登录名单须在执行前取得授权。
|
||
|
||
## 4. 阶段与放行条件
|
||
|
||
### P0:前置条件和变更契约(不改业务行为)
|
||
|
||
交付:
|
||
|
||
1. 确认当前未提交工作由谁负责,将基线固定到可复现提交;在干净、明确基线之上新建实施分支,不擅自 stash/reset 用户改动。
|
||
2. 核实单台 Linux 机器的 systemd、用户服务、Xvfb、字体、浏览器依赖、sandbox、可用磁盘;取得合法原生指纹浏览器并固定版本,指定用于 A02 普通升级验证的源版本与目标版本。
|
||
3. 记录可用的旧方式性能/磁盘基线。默认不运行 Docker;如无历史可信数据,性能改善明确标记未验证,不用新建旧浏览器对照冒充基线。
|
||
4. 列出受影响状态码、载荷、字段、配置和移除项,批准第三节契约。明确 gateway 重启后受管 runtime 的恢复行为。
|
||
5. 固定验证参数:任务最长时间、清理时间预算、任务使用权续租/过期时间、磁盘下限、并发数、日志保留及资源对比指标。
|
||
|
||
放行:没有原生浏览器、必要指纹参数不被支持、sandbox 无法启用、没有批准破坏性契约时,停在此阶段并给出明确缺口;不得偷偷切到普通 Chromium、`--no-sandbox` 或旧 Docker。
|
||
|
||
### P1:gateway 原生生命周期(与 P2 组成第一个端到端切片)
|
||
|
||
先写失败测试,再实现:
|
||
|
||
- 提取并保留现有与 Docker 无关的代理、CDP、页面动作;将 gateway 包和测试从 Docker 命名改为浏览器领域命名,建议目标路径 `browser_gateway/`。
|
||
- 原生启动输入校验在创建目录/进程之前完成:节点、环境、代次、浏览器版本、Profile、代理绑定及必要资源容量。
|
||
- 创建前落盘运行意图;用 runtime 专属 unit/临时目录启动 Xvfb 和浏览器,分配不冲突的 display 与端口。Profile 独占不能只靠控制面内存锁。
|
||
- 默认不继承 `--no-sandbox`;浏览器与 gateway 以非 root 身份运行。具体 sandbox 模式由目标二进制/发行版证明。
|
||
- 创建失败逆序回收已经创建的资源;停止为有界的优雅退出、OS 终止与目录清理。
|
||
- 短任务有自我终止上限,runtime 独立于 gateway 进程存活但不永久失管;长期会话在 gateway 重启后核对 unit/目录/代理与代次,不随意接管别的 CDP。
|
||
- gateway snapshot/health 返回实际 runtime 与待清理信息;“进程在”不能冒充浏览器可用。
|
||
|
||
最小检查:创建/就绪/停止、部分启动失败、并发分配、Profile 冲突、重复清理、旧代次删除、gateway 重启识别、未知资源拒绝删除;四类代理及支持的认证配置分别覆盖连接成功、认证失败和网络失败,不直连。实际浏览器证据按 A09/B03/D05 另行手工验收。
|
||
|
||
放行:单节点不需要 Docker daemon/socket 可完成真实人工登录和停止再开,账号仍保持登录;gateway 单元覆盖率至少 65%。
|
||
|
||
### P2:控制面连接原生 runtime(首个可用闭环)
|
||
|
||
先测试控制面与 gateway 的成功、校验、失败、冲突、响应丢失路径,再改:
|
||
|
||
- `hub.go` 的创建、启动、停止、状态核对和 cleanup-pending 改用 generation/owner;删除容器和网络代次依赖。
|
||
- `internal/environment/store.go`、相关查询与 schema 改为原生版本/运行模型;开发数据库受控重建,不回填旧容器字段。
|
||
- 继续复用既有多 gateway 登记、路由和心跳;核对稳定机器身份。节点 Endpoint 的更换不能改写既存 cleanup 的目的地。
|
||
- 代理服务不再依赖 Docker IP/网络,仍保留代理绑定代次和失败可见性;从目标 gateway 的实际浏览器路径验证出口。
|
||
- 登录二维码、账号身份快照、恢复事件订阅全部使用新 runtime 身份;不能随运行代次变化清空业务事件去重、基线和已占用 UID 冷却。先用确定性测试覆盖重启/重连、冷却内新事件、冷却到期旧事件及迟到事件不补发;真实平台按 C02/D04 验收。
|
||
- 接入停止后的普通浏览器版本升级,复用原 Profile 与稳定指纹;启动后核对实际版本及账号身份,不通过新建环境或重置账号资料实现升级。
|
||
- 同阶段交付首个闭环所需的 Refine data provider 适配、已安装版本选择/普通升级、登录、显式启停与采集入口;环境页区分定义与运行状态,任务页分别展示业务结果、清理状态和明确错误,不只写日志。覆盖节点不可达、版本缺失、Profile 占用、待清理及禁用状态的交互测试,不推迟至 P4。
|
||
- 本阶段即接入最小任务归属:仅对空闲专用采集账号申请独占使用权,自动创建、执行并用独立有界上下文回收;创建前登记资源 owner,正常/失败都释放。借入长期会话、多任务续租和素材崩溃恢复在 P3 完成,不以无归属的临时启动代码作为中间方案。
|
||
- 一台 gateway 的不可达不能阻塞其他节点的续租/状态更新;在现有机制上做有界隔离,不增加第二套 scheduler。
|
||
|
||
放行:一台 gateway 上从界面完成“手工登录 → 按需采集一个指定账号 → 正确存储结果 → 释放本任务 runtime/临时文件 → 再次启动无需重新登录”。停止、清理及失败状态从界面可见;按 A02 验证普通升级后实际版本切换且 Profile、指纹、登录身份保持。新运行身份下自动响应去重/冷却的确定性回归检查通过;C02/D04 的真实平台恢复与多机证据在 P4 最终放行前补齐,不能用代码检查标记手工用例通过。
|
||
|
||
### P3:采集任务和素材的完整资源归属
|
||
|
||
这是本次磁盘问题的根本修复,不只做 `finally`:
|
||
|
||
1. 任务分配在实际执行前申请使用权,标明任务自建 runtime 或借入已有会话。优先使用专用采集账号;Profile 被监听/人工登录占用时明确等待或冲突,不抢占。
|
||
2. 对 source/素材执行 lease 续租,执行 token 覆盖写结果、发布产物和清理。旧 lease 到期的执行不得提交/覆盖新执行结果。
|
||
3. 成功、失败、取消、超时均走独立有界清理上下文;取消后的业务收尾同样不能用已取消 context,避免永久 running。
|
||
4. 控制面与每台 gateway 各清理自己创建的文件。任务临时资源登记不使用跨机任意路径删除接口。
|
||
5. 素材写本次执行独有的目录;结果不可变发布与 DB token 检查构成同一业务提交边界。先防止旧执行覆盖新文件,再增加孤儿文件清理。
|
||
6. 业务完成和 cleanup 完成分别保存。失败记录有错误、次数和下次重试;周期核对只处理本节点受管残留,不按文件年龄扫整个目录。
|
||
7. 缓存尽可能落到 runtime 目录;持久 Profile 离线清理经过版本验证的缓存白名单。诊断日志有明确上限;正式素材不属于临时清理。
|
||
8. 活跃监听/人工会话与任务页面分别持有使用权。最后一个短任务退出可以结束其自建 runtime,但不能结束仍有合法长期持有者的 runtime;不引入无限空闲复用池。
|
||
|
||
最小检查:所有业务终态、采集超十分钟仍有效续租、旧 token 迟到、数据库提交结果未知、控制面强杀、gateway 强杀、磁盘满、删除失败、两任务同 Profile、监听与采集并行、另一机器同名环境。
|
||
|
||
放行:每种终态均有资源前后清单;正式素材/登录信息不受影响;残留可解释且有界,失败不隐瞒。
|
||
|
||
### P4:界面、部署与清理旧路径
|
||
|
||
- 在 P2 已可用的版本选择/普通升级、启停及任务状态界面上,完成浏览器版本管理与各节点可用情况展示;移除无效的镜像拉取、构建、容器/网络操作。
|
||
- 扩展 P2 的 Refine data provider 和交互测试,覆盖 P3 完整资源归属及多节点场景;保留业务结果、清理状态、错误和禁用原因分别可见,不把首个闭环必需的界面工作留到本阶段。
|
||
- 增加可重复部署的 gateway/原生 runner 用户服务配置和本机浏览器安装说明。跨重启保留节点 ID、Profile、版本配置和运行清单。
|
||
- 若 runtime 允许跨 gateway 重启存活,其临时目录必须由 runtime unit 归属,不能放在 gateway 重启就被 systemd 删除的 `RuntimeDirectory` 中。大型缓存/下载明确使用配置的数据磁盘,不因“临时”二字默认放进 `/run` 的 tmpfs 而转为大量内存占用。
|
||
- 修改 `scripts/dev-backend.mjs`、开发脚本、Dockerfile/Compose 的旧 gateway 相关配置;默认裸启动 Go/Python/Vite,不悄悄启动 Docker browser gateway。
|
||
- 删除 Docker browser wrapper、拉镜像/构建/网络/卷管理及相关测试、配置;PostgreSQL 等仍使用 Docker 的独立部署资产可保留,逐项说明,不做无关清理。
|
||
- `AGENTS.md`、README、部署说明、架构说明、E2E 文档全部对齐。删除旧入口,不保留“失败就回退 Docker”。
|
||
|
||
放行:验证文档全部适用项有证据;静态检查中浏览器链路没有 Docker 依赖;单节点局域网手工验收通过。多节点项记录为后续目标。
|
||
|
||
## 5. 改动定位与顺序约束
|
||
|
||
| 范围 | 主要定位 | 必须一起变化的内容 |
|
||
| --- | --- | --- |
|
||
| gateway 执行 | `browser_gateway/server/http.py`、`runtime.py`、`proxy.py`、`browser/`、`platform/` 及其测试 | 原生 runner、版本/端口/Profile、unit 生命周期、snapshot、代理恢复 |
|
||
| 控制面 lifecycle | `internal/controlplane/api/environments.go`、`internal/controlplane/app/app.go`、environment tests | generation、owner、清理/心跳、多 gateway 错误隔离 |
|
||
| 采集与监听 | `internal/controlplane/api/creator.go`、`internal/controlplane/api/creator_events.go`、`internal/creator/source_lease.go`、`content.go` | 使用权、续租、独立收尾、事件边界与身份核对 |
|
||
| 素材 | `internal/controlplane/api/creator_material.go`、`internal/creator/material.go`、素材测试 | 临时目录、不可变发布、token、崩溃清理 |
|
||
| 数据模型 | `internal/environment/`、`internal/creator/` | 删除 Docker 字段,明确开发重建;业务结果与清理状态分离 |
|
||
| 前端 | 现有 gateway/环境/镜像/任务相关组件及 data provider | 对应契约、失败/禁用交互;不重做导航和视觉体系 |
|
||
| 部署/文档 | `scripts/`、`compose*.yaml`、Dockerfile、`deploy/`、README、`docs/` | 原生安装和联调;旧路径移除;手工验收地址 |
|
||
|
||
顺序限制:产物执行隔离先于孤儿文件清理;本地单任务闭环先于多机压测;所有权和代次先于通用自动清理;不能先删 Docker 实现再留下无法登录的中间交付。
|
||
|
||
## 6. 验证及交付方式
|
||
|
||
- 每个非平凡行为改动先有会在旧实现下失败的测试;单元覆盖率至少 65%。Go 全量测试、vet、build,生命周期/并发相关变更跑 race;Python 非交互测试与覆盖率;前端从 lockfile 安装并测试、构建。
|
||
- 更改 Docker/Compose 文件执行 `docker compose config --quiet`;不默认构建/运行任何 Docker 镜像。旧基线测试需另行得到用户同意。
|
||
- 功能验收不使用浏览器自动化或批量 API 代替用户操作。提供 `0.0.0.0` 监听的本地环境和单节点 gateway 地址,由用户按验证文档手工确认。
|
||
- 资源观测、日志读取和单元测试可以自动执行,但不能因此将真实登录、采集、发送或多机故障验收标为通过。
|
||
- 本文不把服务启动、数据库重建或遗留资源删除当作自动交付动作;需要真实联调时按部署和验证文档由授权操作者启动,并报告当次局域网地址。
|
||
|
||
## 7. 切换与失败恢复
|
||
|
||
1. 经用户确认冻结旧运行、记录账号/节点/版本与需要保留的资料。旧 Docker 卷、用户 Profile、数据库及素材都不能未经授权删除。
|
||
2. 原生环境使用全新开发数据可重新登录;不在应用里实现旧 Docker Profile 迁移或双读。若要求保留既有登录,单独确认一次性受控操作及浏览器版本一致性。
|
||
3. 停止旧浏览器执行后才能启用新路径,不能让同账号新旧环境同时工作。
|
||
4. 如新环境验收失败,停止新任务、保留证据、修复再验。紧急恢复旧版只能是人工恢复到明确版本和匹配数据,须取得授权;不是运行时隐式回退。
|
||
5. 验收后,经授权回收旧浏览器容器/卷/网络与镜像。只删除确认属于旧 CreatorHub 浏览器的资源,禁止全机 `docker system prune` 或按相似名称批量删除。
|
||
|
||
## 8. 实施与验收记录
|
||
|
||
- [x] Linux/systemd、Xvfb 与原生指纹浏览器部署条件满足;非 root gateway 已完成 smoke。
|
||
- [x] 独立 runtime 的 gateway 重启恢复和短任务有界清理已通过自动/真实 smoke;正式参数为租约 60 秒、续租 20 秒、清理 30 秒、恢复 60 秒。
|
||
- [x] 账号 Profile 保留、采集独占/借用边界、无自动跨机迁移已写入契约;同 Profile 真实并发仍需授权操作者手工验收。
|
||
- [x] API/schema/配置的破坏性开发切换范围已固定;不保留旧 Docker 浏览器兼容路径。
|
||
- [x] 完整网页远程桌面未作为本目标能力;需要时另立需求,不能把 gateway 的 Xvfb 误称为远程桌面。
|
||
- [x] 20 GB 磁盘下限、1 GB runtime 日志、20 GB Profile 缓存、并发 1/2 和 `0.0.0.0:8082` 已配置并记录。
|
||
|
||
自动检查结果见 [单节点验证记录](evidence/native-browser-verification-2026-09-18.md)。真实账号、代理、LAN 和破坏性资源用例仍须由授权操作者完成;未执行项不视为通过。
|