mirror of
https://github.com/openai/codex.git
synced 2026-10-21 07:42:01 +00:00
Keep TUI reconnect attempts running until the shared deadline (#48318)
## Why The five-attempt limit could stop reconnection before the existing 120-second budget expired, preventing recovery from longer temporary failures. ## What changed Continue retrying with an eight-second delay after the initial backoff until reconnection succeeds or the shared deadline expires. ## Testing Update the exhaustion test to require the full 120-second budget. Extend the integration test to recover after five failed `thread/resume` attempts and verify draft preservation and notification delivery. GitOrigin-RevId: 321d4ad100dbec1254bfe8aafd67ff63fb9a6e93
This commit is contained in:
@@ -51,7 +51,7 @@ pub(super) async fn reconnect(
|
||||
// Connecting already has transport deadlines. Give healthy history/inventory hydration one
|
||||
// shared budget instead of repeatedly discarding its progress on a short per-attempt timer.
|
||||
let deadline = tokio::time::Instant::now() + Duration::from_secs(/*secs*/ 120);
|
||||
for delay in [0, 1, 2, 4, 8] {
|
||||
for delay in [0, 1, 2, 4].into_iter().chain(std::iter::repeat(/*elt*/ 8)) {
|
||||
let attempt = async {
|
||||
tokio::time::sleep(Duration::from_secs(delay)).await;
|
||||
let client = crate::app_server_connection::connect(&target).await?;
|
||||
|
||||
@@ -618,7 +618,7 @@ async fn reconnect_exhaustion_and_unknown_initial_thread_stay_offline() -> Resul
|
||||
.is_err()
|
||||
);
|
||||
}
|
||||
assert!((15..=65).contains(&start.elapsed().as_secs()));
|
||||
assert_eq!(start.elapsed().as_secs(), 120);
|
||||
app.begin_reconnect();
|
||||
app.chat_widget.reconnect_failed();
|
||||
assert_snapshot!(
|
||||
|
||||
@@ -43,7 +43,7 @@ async fn automatic_reconnect_restores_draft_and_routes_new_notifications() -> Re
|
||||
"cliVersion": "0.0.0", "source": "cli", "turns": [{"id": "running", "items": [], "status": "inProgress", "error": null}]
|
||||
});
|
||||
// The first connection checks daemon compatibility before TUI startup.
|
||||
for connection in -1..3 {
|
||||
for connection in -1..7 {
|
||||
let mut socket = loop {
|
||||
let (stream, _) = listener.accept().await?;
|
||||
// Startup probes the default daemon socket before opening its WebSocket.
|
||||
@@ -69,7 +69,8 @@ async fn automatic_reconnect_restores_draft_and_routes_new_notifications() -> Re
|
||||
if connection == 1 && request.method == "initialize" {
|
||||
restore_rx.take().unwrap().await?;
|
||||
}
|
||||
if connection == 1 && request.method == "thread/resume" {
|
||||
// Keep failing past the original five-attempt limit.
|
||||
if (1..=5).contains(&connection) && request.method == "thread/resume" {
|
||||
socket
|
||||
.send(Message::Text(
|
||||
json!({"id": request.id, "error": {
|
||||
@@ -131,7 +132,7 @@ async fn automatic_reconnect_restores_draft_and_routes_new_notifications() -> Re
|
||||
.into(),
|
||||
))
|
||||
.await?;
|
||||
if connection == 2 && request.method == "thread/resume" {
|
||||
if connection == 6 && request.method == "thread/resume" {
|
||||
// Keep the recovered turn running: its output must appear without waiting
|
||||
// for turn/completed or rebuilding the transcript.
|
||||
socket
|
||||
@@ -162,7 +163,7 @@ async fn automatic_reconnect_restores_draft_and_routes_new_notifications() -> Re
|
||||
"preserved-draft!",
|
||||
"fresh-notification-after-reconnect",
|
||||
] {
|
||||
let deadline = Instant::now() + Duration::from_secs(/*secs*/ 30);
|
||||
let deadline = Instant::now() + Duration::from_secs(/*secs*/ 60);
|
||||
while !terminal.screen_contains(expected) && Instant::now() < deadline {
|
||||
terminal.read_output(Duration::from_millis(/*millis*/ 20))?;
|
||||
}
|
||||
@@ -205,7 +206,7 @@ async fn automatic_reconnect_restores_draft_and_routes_new_notifications() -> Re
|
||||
.iter()
|
||||
.filter(|method| *method == "thread/resume")
|
||||
.count(),
|
||||
2
|
||||
6
|
||||
);
|
||||
assert!(!methods.iter().any(|method| method == "turn/start"));
|
||||
Ok(())
|
||||
|
||||
Reference in New Issue
Block a user