From 0a4fdcb8cdbfeb3457a1180566171e14cf18421a Mon Sep 17 00:00:00 2001 From: ManhND Date: Tue, 23 Jun 2026 23:34:25 +0000 Subject: [PATCH] Improve error handling: log previously silenced failures in recovery and stream paths - relay_switch.rs: Log rollback save failure and settings load fallback - relay_config.rs: Log failed file restoration during config write rollback - launcher.rs: Log stream chunk errors, helper connection failures, and failure status persistence errors - watcher.rs: Log spawn_launcher failures - provider_sync.rs: Log restore_session_changes failure during rollback All error recovery and rollback operations now emit diagnostic log entries when they fail, making silent failures observable without changing the control flow or error propagation semantics. Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- crates/codex-plus-core/src/launcher.rs | 38 +++++++++++++++++---- crates/codex-plus-core/src/relay_config.rs | 20 +++++++++-- crates/codex-plus-core/src/relay_switch.rs | 21 ++++++++++-- crates/codex-plus-core/src/watcher.rs | 11 +++++- crates/codex-plus-data/src/provider_sync.rs | 10 +++++- 5 files changed, 88 insertions(+), 12 deletions(-) diff --git a/crates/codex-plus-core/src/launcher.rs b/crates/codex-plus-core/src/launcher.rs index 6eb9fcbbb..0ce4c4540 100644 --- a/crates/codex-plus-core/src/launcher.rs +++ b/crates/codex-plus-core/src/launcher.rs @@ -331,7 +331,15 @@ where } let message = error.to_string(); let failure = launch_status("failed", &message, debug_port, helper_port, &app_dir); - let _ = status_store.save_latest(&failure); + if let Err(save_err) = status_store.save_latest(&failure) { + let _ = crate::diagnostic_log::append_diagnostic_log( + "launcher.save_failure_status_error", + serde_json::json!({ + "error": save_err.to_string(), + "context": "failed to persist launch failure status" + }), + ); + } hooks.write_status("failed").await; Err(error) } @@ -471,7 +479,15 @@ impl LaunchHooks for DefaultLaunchHooks { accepted = listener.accept() => { if let Ok((stream, addr)) = accepted { tokio::spawn(async move { - let _ = handle_helper_connection(stream, Some(addr)).await; + if let Err(err) = handle_helper_connection(stream, Some(addr)).await { + let _ = crate::diagnostic_log::append_diagnostic_log( + "launcher.helper_connection_error", + serde_json::json!({ + "error": err.to_string(), + "addr": addr.to_string() + }), + ); + } }); } } @@ -1041,10 +1057,20 @@ async fn handle_protocol_proxy_connection( if upstream.wire_api == crate::protocol_proxy::UpstreamWireApi::Responses { let mut bytes_stream = upstream.response.bytes_stream(); while let Some(chunk) = bytes_stream.next().await { - if let Ok(bytes) = chunk { - stream.write_all(&bytes).await?; - } else { - break; + match chunk { + Ok(bytes) => { + stream.write_all(&bytes).await?; + } + Err(err) => { + let _ = crate::diagnostic_log::append_diagnostic_log( + "launcher.stream_chunk_error", + serde_json::json!({ + "error": err.to_string(), + "context": "upstream stream chunk read failed" + }), + ); + break; + } } } log_helper_response( diff --git a/crates/codex-plus-core/src/relay_config.rs b/crates/codex-plus-core/src/relay_config.rs index 0c0b606ad..a893c6d1b 100644 --- a/crates/codex-plus-core/src/relay_config.rs +++ b/crates/codex-plus-core/src/relay_config.rs @@ -1091,9 +1091,25 @@ fn write_codex_live_atomic( if let Some(config_text) = config_text { if let Err(error) = crate::settings::atomic_write(&config_path, config_text.as_bytes()) { if auth_written { - let _ = restore_optional_file(&auth_path, old_auth.as_deref()); + if let Err(restore_err) = restore_optional_file(&auth_path, old_auth.as_deref()) { + let _ = crate::diagnostic_log::append_diagnostic_log( + "relay_config.rollback_auth_restore_failed", + serde_json::json!({ + "error": restore_err.to_string(), + "path": auth_path.display().to_string() + }), + ); + } + } + if let Err(restore_err) = restore_optional_file(&config_path, old_config.as_deref()) { + let _ = crate::diagnostic_log::append_diagnostic_log( + "relay_config.rollback_config_restore_failed", + serde_json::json!({ + "error": restore_err.to_string(), + "path": config_path.display().to_string() + }), + ); } - let _ = restore_optional_file(&config_path, old_config.as_deref()); return Err(error.context("写入 config.toml 失败")); } } diff --git a/crates/codex-plus-core/src/relay_switch.rs b/crates/codex-plus-core/src/relay_switch.rs index 6a84d37a9..ec436fdb5 100644 --- a/crates/codex-plus-core/src/relay_switch.rs +++ b/crates/codex-plus-core/src/relay_switch.rs @@ -25,7 +25,16 @@ pub fn switch_relay_profile_in_home( anyhow::bail!("供应商配置总开关已关闭,未写入 config.toml / auth.json。"); } - let original_settings = store.load().unwrap_or_default(); + let original_settings = store.load().unwrap_or_else(|err| { + let _ = crate::diagnostic_log::append_diagnostic_log( + "relay_switch.load_original_settings_failed", + serde_json::json!({ + "error": err.to_string(), + "context": "falling back to default settings for rollback snapshot" + }), + ); + BackendSettings::default() + }); if !previous_active_relay_id.trim().is_empty() && previous_active_relay_id != selected_settings.active_relay_id { @@ -42,7 +51,15 @@ pub fn switch_relay_profile_in_home( match apply_selected_relay_profile(home, &selected_settings) { Ok(result) => Ok(result), Err(error) => { - let _ = store.save(&original_settings); + if let Err(rollback_err) = store.save(&original_settings) { + let _ = crate::diagnostic_log::append_diagnostic_log( + "relay_switch.rollback_save_failed", + serde_json::json!({ + "error": rollback_err.to_string(), + "context": "failed to restore original settings after relay profile apply error" + }), + ); + } Err(error) } } diff --git a/crates/codex-plus-core/src/watcher.rs b/crates/codex-plus-core/src/watcher.rs index 8a9965bac..421376f4a 100644 --- a/crates/codex-plus-core/src/watcher.rs +++ b/crates/codex-plus-core/src/watcher.rs @@ -315,7 +315,16 @@ fn spawn_launcher(launcher_path: &Path, debug_port: u16) { .stderr(Stdio::null()); use std::os::windows::process::CommandExt; command.creation_flags(crate::windows_integration::CREATE_NO_WINDOW); - let _ = command.spawn(); + if let Err(err) = command.spawn() { + let _ = crate::diagnostic_log::append_diagnostic_log( + "watcher.spawn_launcher_failed", + serde_json::json!({ + "error": err.to_string(), + "exe": exe, + "debug_port": debug_port + }), + ); + } } } diff --git a/crates/codex-plus-data/src/provider_sync.rs b/crates/codex-plus-data/src/provider_sync.rs index 61bc0dbb3..a759db944 100644 --- a/crates/codex-plus-data/src/provider_sync.rs +++ b/crates/codex-plus-data/src/provider_sync.rs @@ -223,7 +223,15 @@ pub fn run_provider_sync_with_target( let (sqlite_updates, updated_workspace_roots) = match apply_result { Ok(counts) => counts, Err(err) => { - let _ = restore_session_changes(&applied.changes); + if let Err(restore_err) = restore_session_changes(&applied.changes) { + let _ = codex_plus_core::diagnostic_log::append_diagnostic_log( + "provider_sync.restore_session_changes_failed", + serde_json::json!({ + "error": restore_err.to_string(), + "context": "failed to restore session changes after apply error" + }), + ); + } return Err(err); } };