从号源解析到评论入库的全链路工程实践 —— 签名快路径、异步队列、抗风控、多租户隔离。
Next.js 16 App Router · SSR · Vercel Cron 触发 · 中间件 + RLS 双层鉴权。Cron 路由独立 CRON_SECRET 校验,与用户路径解耦。
FastAPI + Playwright + f2 签名 · 1GB VM 单 Chromium · 30s 队列 poller。对外接口全部 FLY_WORKER_SECRET bearer 校验。
16 个 migration · RLS tenant_scope 政策 · scrape_jobs 即队列 · result JSONB 写实时进度。三层之间只通过 DB + HTTP 通信,无中间件。
单条评论页拉起浏览器约需 10–15 s,1GB Fly VM 只能跑一个 Chromium 实例。改用 f2.crawlers.douyin.web.abogus 对 a_bogus 算法签名,httpx 直接命中 /aweme/v1/web/comment/list/,异常时静默回退 Playwright 兜底。
性能基线(2026-05-05 实测)
| 指标 | 数值 |
|---|---|
| 活跃号源 | 31 |
| 子任务总数 | 176(31 new + 145 refresh) |
| 总耗时 | 5 min 12 s |
| 单号源平均 | 9.1 s |
| 单号源异常阈值 | ≥ 60 s 视为 Playwright fallback 命中 |
| 失败数 | 0 |
依赖锁定:f2==0.0.1.7 硬依赖 httpx==0.27.2,不得随意 bump。f2 失效预案见 claude-memory · feedback_comment_api_f2(Evil0ctal abogus 切包路径)。
从 Fly Tokyo 出口 IP,下列查找路径 全部失效,不要重试:
| 失效路径 | 返回 |
|---|---|
/@{handle} | 重定向到首页 |
/aweme/v1/web/discover/search/ | data: [] |
/aweme/v1/web/general/search/single/ | data: [] |
user/profile/other?other_unique_id | UserId 不合法 |
v.douyin.com/xxx 短链 302 跳转 —— 服务端跳转不走 SPA 路由也不受地理封锁,Playwright goto() 跟随到 /user/{sec_uid}。落地为 worker /scrape/resolve-share-batch + API /api/sources/import-batch,这是号源录入的 唯一标准路径,UI 上手动输入 sec_uid 已降级。scrape_jobs 表四态状态机:pending / running / completed / failed。result JSONB 字段保存实时进度,前端 useScrapeJob hook 2 s 轮询并 localStorage 恢复。
语义变更:2026-04-23 起号源抓取的「成功」≠「新增评论」,老视频 refresh 回 0 条评论是正常的(评论区无变化),UI Badge 显示的是 new_comments_inserted 累计。
mark_account_failure RPC · scraper / sender / discoverer 全埋点 · 前端 Resume / Ban 操作 · 20 测试通过。jitter_ms() 替换全部 wait_for_timeout(±30%)· STEALTH_INIT_SCRIPT 由 4 项扩到 7 项(WebGL/canvas 噪声/permissions/chrome.runtime/...)· 67 测试 · /health 200。Postgres tenant_scope 政策统一管控 org_id,WHERE org_id IN app.accessible_org_ids()。绕不过去。
requireAuth / Staff / OrgMember / Owner 四档守卫,角色差异在路由层区分。
操作按钮按角色禁用 · 第三层兜底 · 体验上避免误触。OrgProvider 注入会话上下文。
accounts.org_id NOT NULL,无共享池 fallback,新 org 必须自己绑卡。14 天 1206 jobs,失败 59 条 ——
| 失败原因 | 条数 | 归因 |
|---|---|---|
zombie_running 清理(管理员手动) | 29 | 非真失败 |
| no active scraping account(cookie 过期) | 26 | 业务层 |
Page.goto Timeout | 2 | 网络抖动 |
| context destroyed | 2 | 浏览器层 |
| IP / 网络封锁 | 0 | 不存在 |
scrape-failure-rate.ts 连续 7 天 >15%;② 失败原因分布出现新桶(PROXY error / IP block);③ 业务量翻倍 + WDA 退役需切回 Web 发送。