公开页抓取改为 Chrome 136 自洽身份 + 每节点 SQLite 养罐,Trafilatura 走 curl_cffi;MCP/README/接手说明与 09-02 现网复测对齐,避免消费方继续抄过期的站点三分表。 Co-authored-by: Cursor <cursoragent@cursor.com>
125 lines
6.6 KiB
Markdown
125 lines
6.6 KiB
Markdown
---
|
||
type: runbook
|
||
status: active
|
||
created: 2026-09-02
|
||
---
|
||
|
||
# 接手开发说明
|
||
|
||
> 读者:第一次改这个仓的工程师 / Agent。读完应能:找到权威文档、在本机跑通测试、知道改哪一层、知道什么不能做。
|
||
> 决策权威:[`plan-final-20260901.md`](plan-final-20260901.md)。机制权威:[`design-arch-20260901.md`](design-arch-20260901.md)。现网能力:[`mcp-usage-20260901.md`](mcp-usage-20260901.md) §4。仓库地图:根 [`README.md`](../README.md)。
|
||
|
||
## 0. 十分钟路径
|
||
|
||
1. 读根 `README.md` §1–§3(问题、分层、入选方案)。
|
||
2. 读本文 §1–§4(目录、事件、怎么改、怎么验)。
|
||
3. `cd server && go test -race ./...` 必须绿。
|
||
4. 再按任务读:路由 → `internal/scheduler/routing.go`;抓取 → `stacks/trafilatura/app.py` + `internal/dock/`;合规 → `internal/policy/`;MCP 契约 → `internal/gateway/mcphandler.go`。
|
||
|
||
不要从 `.dsh/contracts/` 或 superseded 手稿当现行 acceptance。过程产物在 `.dsh/artifacts/`(gitignore)。
|
||
|
||
## 1. 进程与包
|
||
|
||
单二进制三角色,Swarm 里三个服务:
|
||
|
||
| `-role` | 职责 | 有状态 |
|
||
|---|---|---|
|
||
| `gateway` | MCP `/mcp`、HTTP `/v1/*`、Auth、策略预检、入队 | 无。可多副本 |
|
||
| `scheduler` | SQLite 队列、能力路由、Dock 适配器、模版层、Cookie 罐 | **有。replicas=1,钉节点** |
|
||
| `proxymanager` | 订阅、探活、选出口 | replicas=1 |
|
||
|
||
适配器在 scheduler 进程内,引擎在旁边的容器(SearXNG / Trafilatura / Lightpanda / shell)。
|
||
|
||
| 要改 | 去哪 | 不要 |
|
||
|---|---|---|
|
||
| 工具参数 / 信封 | `internal/contract/`、`gateway/mcphandler.go` | 只改文档不改 schema |
|
||
| 搜索 junk 过滤 | `scheduler/searx_parse.go` `isJunkSearchHit` | 在适配器里偷偷丢结果 |
|
||
| 精读 TLS/UA | `stacks/trafilatura/app.py`(真抓取) | 只改 Go `httpx` 假装 Chrome |
|
||
| 指纹模版 | `internal/fingerprint/` | 模版和 impersonate 错代 |
|
||
| Cookie 罐 | `internal/session/` + `store/session.go` | 把 Cookie 写进 MCP / jobs JSON |
|
||
| robots / SSRF | `internal/policy/` | fail-open 放行内网 |
|
||
| 出站代理 | `internal/proxymanager/` | 在适配器里自己拨代理 |
|
||
| 部署 | `stacks/browser-server.yml`、`scripts/deploy-mgr1.sh` | 在 Swarm 节点上 `docker pull` |
|
||
|
||
`JobEnvelope.Session` 与 `RawResult.SetCookies` 是 `json:"-"`。打破这条 = Cookie 进审计/MCP,P0。
|
||
|
||
## 2. 事件表(本服务已填、热修只改碰到的行)
|
||
|
||
| 事件 | 怎么活 | 怎么死 | 多快死 |
|
||
|---|---|---|---|
|
||
| search/read 请求 | 认证过 → 入队 ACK → 适配器出 RawResult → 模版层信封 | 策略 `denied`;上游 `blocked`/`upstream`/`timeout` | 入站跟网关;出站 Trafilatura 15s;队列硬顶 120s |
|
||
| 排队位 | running+queued < 60 才接 | 超限 503,只拒新 | 消费者按 `Retry-After` |
|
||
| Cookie 罐 | 200 且非投毒则 Sanitize 后覆盖该域 | 403/验证页/换出口 → 整域删 | TTL 2h,硬顶 6h,60s reap |
|
||
| 指纹模版 | 节点 HOSTNAME 种子,8 套落库,内存只持 active | 不因单次失败换脸 | 进程重启从库恢复同一张脸 |
|
||
| 渲染槽 | Lightpanda 多槽;shell 默认 0 副本 | shell 忙则互斥停接 | 空闲 10min 计数(本版不自动 scale) |
|
||
| 密钥 | `X-Service-Token`,库内 hash | 缺省 fail-closed | 吊销缓存 ≤10s |
|
||
|
||
「用默认超时」不算已填。Go 出站禁止 `http.DefaultClient`。I/O 第一参必须是 `ctx`。
|
||
|
||
## 3. 改代码时的分层
|
||
|
||
```
|
||
消费者 → gateway(认证/配额/SSRF/robots)
|
||
→ scheduler 入队
|
||
→ 路由(region + 是否要渲染)
|
||
→ dock 适配器(只产 RawResult)
|
||
→ 模版层(体积守卫 / fit markdown / 安全扫描 / 信封)
|
||
```
|
||
|
||
新增第 6 个引擎:实现 `init/health/execute/teardown/capabilities`,注册路由标签,**不要**再写一套合规。对照 `docs/overview-integration-20260901.md` §2。
|
||
|
||
P0 指纹自洽:`impersonate`、UA、`sec-ch-ua`、platform 钉同一 Chrome 大版本(现网 136)。Go `httpx` 保持诚实 UA。
|
||
|
||
P1 罐硬顶:每域 20 颗、单条 4KiB、总 2MiB、64 域 LRU。登录态名(`session-token` / `sid` / `__secure-*psid` 等)直接拒收。
|
||
|
||
## 4. 验证
|
||
|
||
合入前:
|
||
|
||
```bash
|
||
make fmt && make vet
|
||
cd server && go test -race ./...
|
||
make wc # 单文件 >600 行必须拆
|
||
```
|
||
|
||
改了 MCP 参数或信封:同步 `docs/mcp-usage-20260901.md` 与 `mcphandler.go` 的 schema,并补/改 golden。
|
||
|
||
改了 Trafilatura:必须重建 `onesvm/trafilatura-http:dev`,只更 Go 镜像是半接线(真抓取在 Python)。
|
||
|
||
现网复测:用 HTTP `/v1/search` `/v1/read` 即可(与 MCP 同一内核)。不要把消费方 key 写进脚本提交。
|
||
|
||
## 5. 部署(🟡,须用户确认)
|
||
|
||
目标是 **primary mgr1 `192.168.1.51`**,不是 dev-swarm。默认 `scripts/deploy-mgr1.sh` 是 dry-run。
|
||
|
||
已知坑(已踩过,不要再踩):
|
||
|
||
1. 生产节点禁直连 Docker Hub;本机构建 amd64 → `save|load` → `--resolve-image never`。
|
||
2. **同 tag `:dev` 覆盖后必须 `docker service update --force`**,否则还跑旧任务。
|
||
3. Lightpanda CDP 握手 `Host` 必须是 `127.0.0.1:9222`,Docker 服务名会被拒。
|
||
4. Trafilatura cgroup 现网是 **192m**(64m 会 OOM 137)。`deploy-prod-preset` 里仍写 64m,以 stack 为准。
|
||
5. 海外 search 出口键用 `https://www.bing.com/`,不要拿空 URL 去 `/api/exit`。
|
||
6. 单次适配器超时不要把整实例健康闩死;只有 `/healthz` 失败或 HTTP 5xx 才摘适配器。
|
||
|
||
回滚:`docker stack rm browser-server`(命名卷保留)。不要 `git push --force`。
|
||
|
||
## 6. 文档怎么维护
|
||
|
||
| 变了什么 | 更新哪 |
|
||
|---|---|
|
||
| 工具参数 / 错误码 / 现网能力 | `mcp-usage-20260901.md`(消费方权威) |
|
||
| 联调步骤 / 验收用例 | `integration-vlepontas-20260901.md` |
|
||
| 决策(档位、Bing-only、不做 L4) | `plan-final`;不要只改 overview |
|
||
| 队列字段 / Dock 五方法 | `design-arch` |
|
||
| 选型理由 | `decision-candidates` |
|
||
| 接手路径 / 现网坑 | **本文** |
|
||
|
||
NFP:规范进组织 `base/`,本仓只写本服务事实。密钥只在 `deploy.env` / 组织 `credentials.md`,禁止写进 docs。
|
||
|
||
## 7. 不要做的事
|
||
|
||
- 为「让 Google 出结果」去伪装 Chrome + Go TLS,或给消费方换出口绕 robots。
|
||
- 把 Amazon 登录 Cookie / TOTP 账号池搬进本服务(DaaS 的实证:决定变量是出口 IP)。
|
||
- 未填事件表就加新中间件(Redis、第二套队列)。
|
||
- 未授权 commit / push;用户没说「确认执行」就 `--apply` 到 mgr1。
|
||
- 用 2026-09-01 bench 的站点三分表覆盖现网 §4(BBC/百科/Amazon 结论已漂移)。
|