Files
creator-hub/docs/native-browser-implementation-plan.md
T

175 lines
19 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 原生浏览器环境:评审后的实施计划
> 状态:实施 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、D05AC-E3)。
- 控制面本机的素材临时文件同样受执行归属和清理约束;旧任务不能覆盖新产物。
- 旧 Docker 浏览器路径彻底删除;构建/测试达标,局域网环境可供用户手工验收,资源对比有实际记录。
## 2. 保持简单的目标结构
```text
React → Go control-plane(账号/任务/绑定/业务结果/素材发布)
└─ native gateway G(单节点;保留后续节点登记契约)
├─ 预安装浏览器版本(所有任务共用只读二进制)
├─ 账号的持久 Profile
└─ runtime generationXvfb + 浏览器 + 临时目录
```
- 继续使用 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。
### P1gateway 原生生命周期(与 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 和破坏性资源用例仍须由授权操作者完成;未执行项不视为通过。