## 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 两版)。
45 lines
2.2 KiB
Markdown
45 lines
2.2 KiB
Markdown
# 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: 前缀覆盖主要组件。
|