Files
creator-hub/docs/realtime-event-push-plan.md
T

72 lines
7.6 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.
# 实时事件推送规划
## 目标与首期边界
用户已确认:复用 douyin-pc 已验证的网页实时通知信号;先实现事件推送,WS 与现有 HTTP 共用网关地址和端口;后续全部网关业务通信迁移到 WS。
首期链路:网页通知立即唤醒 → 网关暂存待确认投递 → WS 主动推送后台 → 数据库事务保存 → 页面 SSE 通知 → 按当前筛选与页码重新读取。
- 只处理点赞、评论、关注、转发;私信仍走独立收件箱,不自动互动。
- 保留真实 UID 核验、Python 解码 64 位通知 ID、只读通知列表、来源和时间语义、监听开关代次及原去重规则。
- 本期其他 HTTP 功能不迁移。已废弃的事件 GET 拉取路径删除,不增加轮询回退。
- 保持现有表结构与检查点,不新增数据库更新脚本。未确认投递在网关保留;进程重启根据持久化检查点完整核对平台仍可返回的历史,不能承诺平台已删除通知也能恢复。
## 通道与消息
### 浏览器 → 网关
复用 douyin-pc 已验证的 NoticeFrontier 回调,在网页已建立的连接上读取通知帧,过滤 700/960/961 分组及对应互动类型,不另建抖音私有协议客户端。固定的已登录通知页面执行等待 Promise,有信号立即返回,空闲超时仅用于身份/存活检查,不表示定时调用通知 API。网关取得原始 JSON 后在 Python 解码、按通知 ID 读取详情并沿用 normalize_notice。
通知信号与初次/周期历史核对使用独立浏览器连接与执行线程,不让完整历史扫描占住实时通道。完整核对仍约每 5 分钟一次,且不截断历史。不能使用扫描头部页代替真实通知信号。
### 网关 → 后台
同地址新增 `/v1/channel`,每个网关复用一条 WS,多个监听账号共享连接。首期消息仅包括 subscribe/unsubscribe、投递批次、ack、错误。携带账号环境 alias、订阅标识、运行代次及每次启动独立的 session_id,拒绝旧订阅投递;同一开关代次重连后,旧停止请求也不能停止新会话。账号启动只持有各自生命周期锁,不占共享订阅注册表锁;订阅验证不等待浏览器操作锁;单账号错误不关闭其他账号通道。
使用成熟 WS 库处理握手、帧、心跳和关闭;不手写协议。接收等待不能持有浏览器 alias 锁;通道读取与账号保存分开,慢账号不阻塞其他账号。只在后台保存成功后确认,未确认批次重连后重送。过载必须显式报错,不静默丢弃事件。
启动/停止监听首期仍使用已有 HTTP 命令,事件拉取和确认迁移到 WS。连接失效明确记录,重连重新订阅并补送;失败不伪装连接正常。
### 后台 → 页面
事务保存成功后发布事件列表变更。复用现有 `/api/creator/updates` SSE 通道和前端 creatorSubscribe,页面收到通知立即刷新当前筛选分页,不直接拼接第一行、不改变排序。首次连接/重连也重新查询数据库,页面断开不影响后台收取。取消页面 5 秒轮询,保留手动刷新,断线明确展示。
SSE 是列表失效通知而非唯一数据存储;服务重启或页面重连以数据库查询恢复,所以无需另建消息中间件。
## 封面与慢任务
事件保存与确认不等待封面、历史补收或未来 AI 分析。封面队列满时,在事件原保存事务写入真实过载原因,不在确认路径额外同步写库;历史核对再尝试下载。封面下载独立处理,成功后清除同一事件的封面错误并发布列表变更;路径由现有作者 UID/作品 ID 本地文件约定解析,不新增路径字段;失败记录真实错误,不阻断事件、不回退远程图片。初次历史与实时投递允许交错;仅全部历史投递确认后推进对应历史检查点,不能要求队列中后来新增的实时投递也已确认。
## 生命周期与可观测性
- 开关代次、运行身份仍由现有事务与浏览器核验约束;关闭阻止旧代次写入。
- 记录通知信号时间、网关接收/发送、后台保存与确认时间,包含网关、alias、通知 ID/投递 ID、批次数量及连接状态。实时与历史投递以 realtime_signal 区分;跨机时间戳差值标记为 clock_delta(受时钟同步影响),WS 发送至保存确认的往返耗时用网关单调时钟测量,不伪造精确跨机延迟。
- 页面断线、WS 断线、通知页身份失败、补收异常、封面错误分别可见,不能把设置开启等同实时正常。
- 建议人工验收目标:从网页信号到保存 P95 ≤ 1 秒,到页面可见 P95 ≤ 2 秒。抖音生成通知的耗时另算;这些是待测目标,不是实施后未经真机验证的保证。
## 测试与完成标准
先写失败测试再实现。Python 覆盖信号唤醒、实时/历史并行、ACK 边界、重送、错误/停止、真实本机 WS 握手与多订阅;Go 覆盖共享连接、断线/取消、持久化后确认、去重/代次与 SSE 变更;前端覆盖即时刷新、重连/断线提示、清理及原筛选/分页。受改业务单元覆盖率 ≥ 65%;运行现有相关回归、antd lint、web 构建及 diff 检查。不自动编写或运行 E2E。
没有平台真机通知证据时,只报告代码/单元验证通过,不声称已实现上述真实延迟指标。douyin-pc 只读参考,不改其代码或混入其未跟踪文档。
## 后续全量 WS 迁移
1. 在同一 `/v1/channel` 增加有请求 ID 的命令/结果,按功能迁移环境启停、身份/资料、采集、私信、状态等全部业务通信。
2. 命令按请求 ID 去重,明确接收、执行完成和结果未确认;断线不自动重发可能产生副作用的操作。文件/截图等明确二进制传输、分块与独立处理,避免大消息阻塞实时事件;不把所有任务放在连接接收线程。
3. 每项迁移完成即删除对应 HTTP 路由与客户端,不保留兼容回退。
4. 最终删除网关全部 HTTP 业务接口,仅保留 WS 标准握手入口,不增加另一个端口;健康/状态也走 WS。
本期不提前实现通用 RPC 框架、未使用命令、配置项或新消息中间件。规划随真实实施结果更新。
## 首期实施与验证记录
- 已实现网页通知唤醒、同端口共享 WS、保存后确认、异步本地封面、复用 SSE 即时刷新;原事件 GET 拉取、前端 5 秒轮询已移除。
- 首期仍保留监听启动/停止及其他网关 HTTP 命令,全量迁移尚未实施,按上节继续。
- Python 网关完整单元回归:176 项通过;本期三个业务模块合计覆盖 92%,各模块 83%–97%。
- Go 全项目测试通过;PostgreSQL 事件/监听相关测试含 race 检查通过。新增通道业务函数覆盖 65%–100%,封面工作线程 97.7%,监听会话 83.9%,封面结果更新 77.3%。这是受影响业务范围的覆盖,不是整个 Go 项目的覆盖率。
- 前端及网页信号 Node 单元测试:19 项通过;事件页覆盖 98.83%;antd lint 无问题,web 构建通过;没有编写或运行 E2E。
- 已检查同代次旧会话停止、共享通道最后订阅关闭与新订阅加入、单账号启动/错误隔离、历史与实时并行、封面过载不额外阻塞确认等边界。
- 部署需同时更新后台与网关,旧事件协议不保留兼容。保留浏览器 profile、指纹与 Cookie,不通过重建环境或清 Cookie 迁移;暂停账号不会因此恢复运行。
- 尚未进行真实抖音通知到数据库、页面的全链路延迟验收;前述 P95 目标仍待人工采样核对,不能以模拟测试、连接成功或通知列表读取成功替代。