Skip to content

Commit 3ff3c20

Browse files
max-sixtyclaude
andcommitted
fix: Add minimum drain wait time for PTY output capture
On Ubuntu CI, the PTY drain loop was exiting prematurely because the kernel returns spurious EOFs before all data is flushed from the buffer. The existing heuristic (4 consecutive EOFs with exponential backoff) wasn't sufficient on slow CI runners under load. Add MIN_DRAIN_WAIT_MS (500ms) that must elapse during drain before accepting stable EOF. This gives the kernel enough time to flush PTY buffers, regardless of how many EOFs we've seen. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 5ab0e10 commit 3ff3c20

File tree

1 file changed

+12
-1
lines changed

1 file changed

+12
-1
lines changed

tests/common/progressive_output.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,13 @@ const OUTPUT_POLL_INTERVAL_MS: u64 = 10;
113113
/// Uses default exponential backoff (10ms → 500ms cap, 5s timeout) for reliability.
114114
const STABLE_READ_THRESHOLD: u32 = 4;
115115

116+
/// Minimum time to wait during drain before accepting stable EOF.
117+
/// On slow CI systems (especially Ubuntu), the PTY may return spurious EOFs before
118+
/// all data has been flushed from the kernel buffer. This ensures we wait long enough
119+
/// for the kernel to complete its PTY buffer flush, regardless of how many EOFs we've seen.
120+
/// 500ms provides enough margin for slow CI runners under load.
121+
const MIN_DRAIN_WAIT_MS: u64 = 500;
122+
116123
/// Strategy for capturing progressive output snapshots
117124
#[derive(Debug, Clone)]
118125
pub enum CaptureStrategy {
@@ -445,8 +452,12 @@ pub fn capture_progressive_output(
445452
match reader.read(&mut temp_buf) {
446453
Ok(0) => {
447454
// EOF - may be spurious on Linux, require consecutive confirmations
455+
// AND minimum wait time to allow kernel buffer flush
448456
consecutive_no_data += 1;
449-
if consecutive_no_data >= STABLE_READ_THRESHOLD {
457+
let min_wait_elapsed = drain_start.elapsed()
458+
>= Duration::from_millis(MIN_DRAIN_WAIT_MS);
459+
if consecutive_no_data >= STABLE_READ_THRESHOLD && min_wait_elapsed
460+
{
450461
break;
451462
}
452463
backoff.sleep(attempt);

0 commit comments

Comments
 (0)