Files
MailUI4Agents/docs/PHASE7-REMAINING.md
JianFeeeee 9d4718a412 feat: SSE Last-Event-ID 补投 + 连接状态指示 + 限速器 DB 化
## SSE Last-Event-ID 补投

EventSource 断线重连时自带 Last-Event-ID 头,但服务端直接忽略了——
所有断线期间的邮件通知都丢失。用户刷新页面也会错过已推的事件。

改为 per-user 事件环形缓冲区(500 条,~100KB/用户,20 在线 ≈ 2MB):
每次 Broadcast/SendToUser/SendToAgent 同时写入对应用户的缓冲区;
AddClient 时取 Last-Event-ID 头,找到该 ID 的位置后从下一条回放。
找不到 ID 说明事件已被覆盖(缓冲区溢出),从头回放全部。

事件 ID 用全局递增序列号(非 UUID),EventSource 的 Last-Event-ID
就是靠这个 ID 记住断点的。

新增测试:缓冲区回放、溢出行为、并发安全(10 goroutine × 200 次 push)、
端到端重连验证(SendToUser → 带 Last-Event-ID 的 AddClient → 补投)。

## 连接状态指示器

Sidebar 用户头像右下角的小圆点:绿=已连接,黄=连接中,橙=重连中,红=断开。
NarrowNav 底栏也有(移动端)。

SSE 模块新增 onSSEStatus/getSSEStatus 接口,onerror/onopen 驱动状态变化。
状态点用 absolute 定位在头像边缘,不遮挡文字。

## 限速器 DB 化(解决多实例部署时的计数漂移)

原实现:LoginLimiter 与 sessionRateLimiter 都是进程内内存计数器。
多实例部署时各自独立计数,等效上限变成 N 倍。

改为 rate_limits 表(bucket + ts),两个限速器共享同一套基础设施:
- LoginLimiter:bucket="login:<username>",COUNT(*) >= 5 → 锁定 5 分钟
- sessionRateLimiter:bucket="session:<agent_name>",COUNT(*) >= 20/h → 拒绝

判断与写入在同一个 BEGIN IMMEDIATE 事务里——SQLite 的 IMMEDIATE
在事务开始时获取 RESERVED 锁,防并发写事务同时进入 COMMIT 阶段。
实测 80 并发下恰好放行 20 次(旧内存版同样通过,但 DB 版才能多实例共享)。

DB 不可用时放行(宁可放开限速也不能让用户完全无法使用)。
新建 rate_limits 表迁移(SQLite + PG 两版)。
2026-09-02 14:33:41 +08:00

2.2 KiB
Raw Blame History

Phase 7 剩余项与已知生产缺陷追踪

无法立即推进(缺 SDK/基础设施)

7.7 DSH 插件dsh-mail-bridge

  • 基于 DeepSeek Harness SDK非 opencode需该 SDK 先装好
  • 与 opencode-mail-bridge 共享同一套 Gateway API
  • 利用 DeepSeek Harness 的 PreToolUse / SessionStart 等钩子

7.8 跨主机 Agent 发现

  • Gateway + Registry 拆分为独立服务
  • etcd / Consul 服务注册与发现
  • Agent 跨主机路由

可以立即推进的生产缺陷

P0 — SSE Last-Event-ID 补投

根因EventSource 断线重连时自带 Last-Event-ID 头,但服务端直接忽略了—— 所有断线期间的邮件通知都丢失。用户刷新页面也会错过已推的事件。 影响:重连后永远看不到断线期间收到的邮件(除非手动刷新)。 修法服务端维护一个有界循环缓冲区ring buffer每次 Broadcast 同时写入, SSE 连接的 handler 在首次连接时从缓冲区头部开始(客户端传了 Last-Event-ID 就从那里), 没有则从头(只带最近 N 条)。缓冲区大小设 500内存 < 2MB。

P0 — 连接状态指示器

根因SSE 断线后前端无任何可见反馈——用户以为系统正常,实际通知已停。 影响:实时性是 Agent 协作的核心体验断线无提示会让人以为「Agent 没在动」。 修法header 旁加一个连接状态点(绿/黄/红SSE 的 onopen/onerror 事件驱动。

P1 — 登录限速跨进程问题

根因LoginLimiter 是进程内内存计数器,多实例部署时每个实例独立计数。 修法:改为 DB 事务rate_limits 表 + IMMEDIATE 事务),多实例共享同一份计数。

P1 — 新建会话限速同理

根因sessionRateLimiter 也是进程内计数器。 修法同上sessionrate.go 重写为调用 RateLimitCheckAndRecord。

P2 — 组件级测试

现状:前端无任何组件测试,前端回归只靠 lint 与构建。 范围关键组件AddressInput 补全、PermissionPanel 决策、WorkCard 预算渲染)。

P2 — 深色主题

现状:只有浅色主题,深夜使用刺眼。 范围tailwind dark: 前缀覆盖主要组件。