fix(transport,pty): gRPC keepalive on both ends; reset local terminal on session end - #12
Merged
Merged
Conversation
PTY sessions died after 40-60 min idle (client saw "error reading from server: EOF"): with no keepalive anywhere, idle connections were reaped by NAT/firewall middleboxes, the server never noticed the dead client, so the attach handler blocked in Recv() forever and activePTY leaked -- every reconnect failed with "pty session already attached" until the server was restarted. The abrupt disconnect also left the local terminal with the remote app's kitty keyboard protocol still pushed, echoing "9;1:3u" fragments on every key release. - transport.Dial: client keepalive (30s/10s, PermitWithoutStream); covers both daemon and pty connections. Behind Caddy the PING terminates at the proxy, which is exactly the segment that was being idle-reaped; no Caddy config change is needed or allowed. - server: KeepaliveParams (30s/10s) plus KeepaliveEnforcementPolicy (MinTime=10s) -- without relaxing the 5min gRPC default, plaintext direct deployments would GOAWAY the 30s client pings. - ptyattach: emit a conservative terminal reset sequence (kitty keyboard pop/zero, modifyOtherKeys, alt screen, bracketed paste, mouse/focus reporting, cursor) on every session end after a successful attach; skipped when dialing failed. Known leftover: attach takeover semantics. Behind Caddy a client that dies without a FIN reaching the proxy can still leak activePTY; direct deployments are now covered by server-side keepalive within ~40s. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
📌 Description
修复 PTY 长连接空闲断连及其两个连锁故障(2026-07-08 实测复现):
error reading from server: EOF,supervisor 联动停掉 daemon;Recv()永不返回,UnregisterPTY不执行,activePTY泄漏——重连一直报pty session already attached,只能重启 server;每次按键回显
9;1:3u之类的 release 事件残片。pkg/transport/client.go:客户端 gRPC keepalive(Time=30s / Timeout=10s /PermitWithoutStream)。daemon 与 pty 共用该拨号入口,两条连接同时覆盖;
空闲 PING 保活的正是被掐断的 client↔Caddy 段。
app/server/main.go:服务端KeepaliveParams(30s/10s)+KeepaliveEnforcementPolicy(MinTime=10s)。后者必须配套:gRPC 默认MinTime=5min,不放宽会把明文直连客户端的 30s PING 判为滥用并 GOAWAY。
死连接触发
Recv报错后走既有 shutdown/UnregisterPTY 清理路径。pkg/config/config.go:keepalive 常量与配对约束说明。pkg/ptyattach/attach.go:新增terminalResetSequence,会话结束的所有路径(正常退出/错误帧/流断开/Ctrl+C)向本地终端写保守复位序列(kitty
键盘协议弹栈清零、modifyOtherKeys、alt screen、bracketed paste、鼠标/
focus 上报、光标形状与可见性);拨号失败(会话未建立)不写。
deploy/tls/Caddyfile.example:补充 keepalive 逐跳语义注释。HTTP/2 PING 逐跳终止:Caddy 前置 TLS 时客户端 PING 只到 Caddy、服务端 PING
只到回源 loopback,Caddy 侧无需且不应做任何配置改动(流级超时禁令不变)。
🔗 Related Issues
Closes #
Refs #
🧪 Testing
make fmt/make lint0 issues /make test全包 ok,test 带 -race)TestGRPCKeepaliveDefaultsPairing守护MinTime < Time 与 Time ≥ 10s 钳制下限;
TestRunCommandDialFailureSkipsTerminalReset;happy-path 断言 stdout 以复位序列收尾)
9;1:3u残留、可直接重连(无 FIN 送达 Caddy)时
activePTY仍可能泄漏;明文直连模式已由服务端keepalive 在约 40s 内兜底。
客户端 Time(有单测守护)。
✅ Checklist
docs/reference/grpc-keepalive.md 为本地文档,docs/ 不入库)
🤖 Generated with Claude Code