8000 fix(deploy): stop SSE streams from exhausting browser HTTP/1.1 connections by sheepbox8646 · Pull Request #836 · felinics/Memoh · GitHub
[go: up one dir, main page]

Skip to content

fix(deploy): stop SSE streams from exhausting browser HTTP/1.1 connections - #836

Merged
qqqqqf-q merged 1 commit into
mainfrom
fix/sse-http2-822
Jul 20, 2026
Merged

qqqqqf-q merged 1 commit into
mainfrom
fix/sse-http2-822

Conversation

@sheepbox8646
Copy link
Copy Markdown
Member

Closes #822

问题

浏览器对同一 origin 的 HTTP/1.1 并发连接上限约 6 条,每条 SSE 流长期独占一条连接。多开标签页 / 多个 bot 会话页时连接配额被占满,后续 REST 请求排队等待,页面整体卡死。

修复内容

后端:所有 SSE 端点发送 X-Accel-Buffering: no

抽出共享的 setSSEHeaders helper,统一覆盖全部 5 处 SSE 端点(session 消息流、bot 活动流、web/stream、bot 创建流、容器创建流、display prepare 流)。nginx 及兼容反代会按响应关闭缓冲,事件即时下发,无需依赖 location 级配置。

nginx:SSE 反代优化

  • Connection: upgrade 改为 map $http_upgrade $connection_upgrade,仅在真正的协议升级请求上传递(原来对所有请求无条件设置,不规范);
  • 为长连接 SSE 端点(sessions/*/messages/events、sessions/events、web/stream)加专用 location:proxy_buffering off、gzip off、读超时拉长到 1h。

nginx:可选 HTTPS + HTTP/2 入口(根治)

  • 新增 8443 端口的 TLS + h2 server 模板,由 docker-entrypoint.d/15-memoh-https.sh 在检测到证书(默认 /etc/nginx/certs/server.crt|key,路径可用 MEMOH_TLS_CERT / MEMOH_TLS_KEY 覆盖)时自动启用,无证书时保持纯 HTTP,行为完全向后兼容;
  • h2 多路复用使单条 TCP 连接承载全部并发流,彻底绕开 6 连接限制;上游仍走 HTTP/1.1,Go 后端无需改动;
  • 主 server 的应用配置抽成共享 include(conf.d/includes/memoh-app.conf),HTTP 与 HTTPS 两个入口行为保持一致;
  • docker-compose.yml 中提供注释掉的 8443 端口映射与证书挂载示例(自签 / mkcert / Let's Encrypt 均可)。

验证

  • 新增 TestBeginSSEResponseSetsProxyFriendlyHeaders 守护 SSE 头契约(TDD:先红后绿);go test ./... 全量通过,golangci-lint 无告警;
  • 用 nginx:alpine 实际渲染模板双模式验证:无证书 → 仅 HTTP、nginx -t 通过;有证书 → HTTPS 入口启用、curl --http2 实测返回 HTTP/2 200;
  • 穿透测试确认路径改写正确:/api/bots/*/sessions/*/messages/events → 去掉 /api 前缀、查询串保留,普通 /api/* 路由不受影响。

未包含(issue 中的可选项)

前端 BroadcastChannel / SharedWorker 共享 SSE 流的兜底方案未包含在本 PR——启用 h2 后收益有限,如仍需要建议单开 issue 跟进。

🤖 Generated with Claude Code

…tions

Browsers cap HTTP/1.1 at ~6 concurrent connections per origin, and every
SSE stream holds one for its lifetime, so a few open bot session tabs
could stall all other requests behind the nginx entrypoint (#822).

- server: send X-Accel-Buffering: no from every SSE endpoint via a
  shared setSSEHeaders helper, so nginx (and compatible proxies) never
  buffer event streams regardless of location-level config.
- nginx: forward Connection: upgrade only for real protocol upgrades
  (map $http_upgrade), and give the long-lived SSE endpoints a dedicated
  location with proxy buffering off, gzip off, and 1h read timeout.
- nginx: add an optional HTTPS + HTTP/2 entrypoint on 8443 that
  15-memoh-https.sh auto-enables when TLS certs are mounted; h2
  multiplexing carries all streams over one TCP connection, removing
  the per-origin connection limit for good. The shared server config
  moved to an include so both entrypoints stay identical; the upstream
  hop stays HTTP/1.1 so the Go backend needs no changes.

Closes #822

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@sheepbox8646
sheepbox8646 requested review from a team July 20, 2026 03:42
@qqqqqf-q qqqqqf-q left a comment
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM。卫生项(X-Accel-Buffering、SSE location、Connection map)是独立于连接耗尽的必要修复;h2 入口可选且向后兼容。注意:无证书的默认部署仍受 #822 根因影响,后续由单独的应用层融流 refactor 跟踪。

@qqqqqf-q
qqqqqf-q merged commit 12bb688 into main Jul 20, 2026
14 checks passed
@chen-ran
chen-ran deleted the fix/sse-http2-822 branch September 11, 2026 12:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: SSE 长连接耗尽浏览器 HTTP/1.1 连接配额导致页面卡死,建议支持 HTTP/2

2 participants

0