Flush large terminal output on Ctrl+C (#631) - #804
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #804 +/- ##
==========================================
+ Coverage 74.17% 74.75% +0.58%
==========================================
Files 99 106 +7
Lines 9017 10099 +1082
Branches 5929 6568 +639
==========================================
+ Hits 6688 7550 +862
- Misses 1723 1855 +132
- Partials 606 694 +88 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Always-on backpressure would pause producers after a short disconnect, which fights ET's reconnect-later model. Stage unsent output in userspace, keep the kernel unsent cap small, and drop the queue only when the user interrupts and the backlog is already large. Co-authored-by: Cursor <cursoragent@cursor.com>
Covers the slow-link recipe (flood, interrupt, prompt next) without a throttle proxy or multi-second soak. Co-authored-by: Cursor <cursoragent@cursor.com>
Move the jumphost pending queue into a testable type so we can assert that only large TERMINAL_BUFFER packets are dropped, then cover the same lossless-interrupt and disconnect-does-not-stall cases with a jumpserver in the middle. Co-authored-by: Cursor <cursoragent@cursor.com>
Exercise a real PTY and interactive shell while limiting the captured output to the flush threshold, proving Ctrl+C reveals the prompt without a costly soak test. Co-authored-by: Cursor <cursoragent@cursor.com>
24ec556 to
0f1ca82
Compare
|
Hi @MisterTea — thanks for this PR. The WriteBuffer + TCP_NOTSENT_LOWAT design is a neat way to make unsent output droppable without touching sequence numbers, and the 64KB threshold keeps normal sessions lossless. One thought on where this could go next, curious about your take: I think a real fix at the code level would be to generalize "flush on Ctrl+C based on estimated drain time" into a continuously enforced latency budget: the sender constantly estimates queued-bytes / recent-throughput, and once the display lag exceeds the budget (say 2 seconds), it proactively drops intermediate output so the screen always stays glued to "now" — essentially mosh-style frame skipping ported to a byte stream. The frozen-screen feeling would disappear at the root, instead of waiting for the user to hit Ctrl+C for a pardon. The cost is equally clear: holes in the scrollback buffer, which undermines ET's core selling point over mosh (lossless scrollback + native terminal semantics). So the sensible shape seems to be an opt-in flag (e.g. One more layer of truth: on slow and lossy links, TCP's own RTO backoff and head-of-line blocking account for a large share of the freezes — that's exactly why mosh built its own reliable transport over UDP in the first place. Switching ET's transport would be major surgery, so in the short term "remote tmux + Ctrl+C when stuck" remains the pragmatic combination. Would an opt-in latency-budget drop policy fit ET's direction, or do you consider scrollback integrity non-negotiable? If it sounds reasonable, I'd be happy to prototype it as a follow-up PR. |
|
I think this will work for standard terminals but not tmux in control mode. In control mode any type of drop could desync the connection. For tmux control mode I think the option to have back pressure is the preferred route |
Ignore SIGPIPE in the test runner (and use MSG_NOSIGNAL on recover writes) so a closed socketpair cannot kill debian jobs, and shut FakeConnection down so coverage runs do not spend minutes generating Universal Stacktrace dumps. Co-authored-by: Cursor <cursoragent@cursor.com>
|
Thanks for the reviews. @xz-dev A continuously enforced latency budget (queued bytes / recent throughput) is a good next step, but it is a different control loop than this PR. Here we only drop unsent @bmaurer Agreed that dropping bytes in tmux control mode can desync the client. This PR does not change HTM / tmux |
Drop pane %output / TTY floods at line boundaries, but retain layout/session/window messages and %begin blocks so a nested control-mode client does not desync. Co-authored-by: Cursor <cursoragent@cursor.com>
|
@bmaurer I added logic to the data drop that detects tmux control sequences and only drops tmux content. The reason we can't go with your backpressure idea is that it breaks workflow for people who expect log-producing commands to keep running while they are disconnected. You can test this yourself by doing
in tmux then disconnecting. With backpressure, the 64kb buffer will fill up and then nvidia-smi will block. Now, replace nvidia-smi with an ML training job and you see how this can be a problem. With this PR, we only deal with backpressure when someone hits ctrl+c. In this mode, someone is already expecting things to get killed so if they lose output spam, it's reasonable. |
…nual iTerm2 GUI test Co-authored-by: MisterTea <306879+MisterTea@users.noreply.github.com> (cherry picked from commit 7c4e9f4)
…ests. Drive a private iTerm2 suite with System Events, screenshot the window, and read the visible buffer so tmux and tmux -CC Ctrl+C recovery no longer needs a human. Co-authored-by: Cursor <cursoragent@cursor.com>
Hold droppable pane output briefly so iTerm2 can issue send-keys while the WriteBuffer is still large, recognize send -t %0 0x3, and prove both modes with the iTerm2 e2e. Co-authored-by: Cursor <cursoragent@cursor.com>
Only watch process stdin when the console fd is stdout, and evaluate peekData into locals before Catch comparisons so GCC/MSVC do not see an empty buffer. Co-authored-by: Cursor <cursoragent@cursor.com>
Summary
BackedWriterpath so long-running jobs do not stall.WriteBufferwithTCP_NOTSENT_LOWAT(and a 64KB unixSO_SNDBUFon etterminal→etserver) so it can actually be dropped. This replaces always-on backpressure/discard from Add opt-in flow control: --flow-control {backpressure,discard} (#631) #730.Test plan
WriteBufferunit tests (enqueue/drain, interrupt bytes, flush threshold, 16MB cap)ServerInterruptDoesNotDropSmallOutput— Ctrl+C with a small queue is losslessServerDisconnectDoesNotStallAt64KB— after client disconnect, 256KB of PTY output is still consumedcat /dev/zero | base64then Ctrl+C: prompt returns in a couple of secondsMade with Cursor