mirror of
https://github.com/openai/codex.git
synced 2026-10-21 17:48:44 +00:00
## Summary - require a Pong within 60 seconds for established Noise Rendezvous WebSockets on both the harness and executor - bound steady-state WebSocket writes and harness event delivery so backpressure cannot mask the deadline - classify executor disconnects with bounded reasons and feed them into the existing reconnect metric and structured log - cover silent peers, responsive peers, continuous non-Pong traffic, and local application backpressure ## Why The existing periodic Pings did not track Pongs, so a half-open or blackholed connection could remain stuck until the operating system's TCP timeout. This adds the smallest explicit liveness contract without new spans, RTT histograms, feature flags, or TCP diagnostics. ## Testing - `just test -p codex-exec-server` on devbox `richard-6` — 300 passed, 2 skipped - `just fix -p codex-exec-server` - `just fmt` - independent correctness, performance/security, and YAGNI reviews — no findings
45 lines
1.1 KiB
Rust
45 lines
1.1 KiB
Rust
use std::time::Duration;
|
|
|
|
use tokio::time::Instant;
|
|
|
|
#[cfg(test)]
|
|
pub(crate) const WEBSOCKET_PONG_TIMEOUT: Duration = Duration::from_millis(100);
|
|
#[cfg(not(test))]
|
|
pub(crate) const WEBSOCKET_PONG_TIMEOUT: Duration = Duration::from_secs(60);
|
|
pub(crate) const WEBSOCKET_PONG_TIMEOUT_REASON: &str = "pong_timeout";
|
|
|
|
/// Tracks whether a WebSocket peer has acknowledged a keepalive ping.
|
|
pub(crate) struct WebSocketPongWatchdog {
|
|
timeout: Duration,
|
|
deadline: Option<Instant>,
|
|
}
|
|
|
|
impl WebSocketPongWatchdog {
|
|
pub(crate) fn new(timeout: Duration) -> Self {
|
|
Self {
|
|
timeout,
|
|
deadline: None,
|
|
}
|
|
}
|
|
|
|
pub(crate) fn ping_sent(&mut self, now: Instant) {
|
|
self.deadline.get_or_insert(now + self.timeout);
|
|
}
|
|
|
|
pub(crate) fn deadline(&self) -> Option<Instant> {
|
|
self.deadline
|
|
}
|
|
|
|
pub(crate) fn write_deadline(&self, now: Instant) -> Instant {
|
|
self.deadline.unwrap_or(now + self.timeout)
|
|
}
|
|
|
|
pub(crate) fn received_pong(&mut self) {
|
|
self.deadline = None;
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
#[path = "websocket_pong_watchdog_tests.rs"]
|
|
mod tests;
|