From f88e848452ca90877612049a4b9b370e94932968 Mon Sep 17 00:00:00 2001 From: Slinetrac Date: Mon, 27 Oct 2025 11:53:31 +0800 Subject: [PATCH] refactor(profile-switch): async post-switch tasks, early lock release, and spawn_blocking for IO --- src-tauri/src/cmd/profile_switch/workflow.rs | 72 ++++++---- .../profile_switch/workflow/state_machine.rs | 127 ++++++++++-------- 2 files changed, 113 insertions(+), 86 deletions(-) diff --git a/src-tauri/src/cmd/profile_switch/workflow.rs b/src-tauri/src/cmd/profile_switch/workflow.rs index 071ec4a8..8726edf7 100644 --- a/src-tauri/src/cmd/profile_switch/workflow.rs +++ b/src-tauri/src/cmd/profile_switch/workflow.rs @@ -135,23 +135,7 @@ pub(super) async fn run_switch_job( Ok(Ok(machine_result)) => match machine_result { Ok(cmd_result) => match cmd_result { Ok(success) => { - handle::Handle::notify_profile_switch_finished( - profile_id.clone(), - success, - notify, - task_id, - ); - close_connections_after_switch(&profile_id).await; - if notify && success { - handle::Handle::notice_message("info", "Profile Switched"); - } - logging!( - info, - Type::Cmd, - "Profile switch task finished: {} (success={})", - profile_id, - success - ); + schedule_post_switch_success(profile_id.clone(), success, notify, task_id); Ok(success) } Err(err) => { @@ -340,16 +324,24 @@ pub(super) async fn restore_previous_profile(previous: Option) -> C } AsyncHandler::spawn(|| async move { - match time::timeout(SAVE_PROFILES_TIMEOUT, profiles_save_file_safe()).await { - Ok(Ok(())) => {} - Ok(Err(e)) => { - logging!( - warn, - Type::Cmd, - "Failed to persist restored configuration asynchronously: {}", - e - ); - } + let save_future = AsyncHandler::spawn_blocking(|| { + futures::executor::block_on(async { profiles_save_file_safe().await }) + }); + match time::timeout(SAVE_PROFILES_TIMEOUT, save_future).await { + Ok(join_res) => match join_res { + Ok(Ok(())) => {} + Ok(Err(err)) => { + logging!( + warn, + Type::Cmd, + "Failed to persist restored configuration asynchronously: {}", + err + ); + } + Err(join_err) => { + logging!(warn, Type::Cmd, "Blocking save task failed: {}", join_err); + } + }, Err(_) => { logging!( warn, @@ -393,6 +385,32 @@ async fn close_connections_after_switch(profile_id: &SmartString) { } } +fn schedule_close_connections(profile_id: SmartString) { + AsyncHandler::spawn(|| async move { + close_connections_after_switch(&profile_id).await; + }); +} + +fn schedule_post_switch_success( + profile_id: SmartString, + success: bool, + notify: bool, + task_id: u64, +) { + AsyncHandler::spawn(move || async move { + handle::Handle::notify_profile_switch_finished( + profile_id.clone(), + success, + notify, + task_id, + ); + if notify && success { + handle::Handle::notice_message("info", "Profile Switched"); + } + schedule_close_connections(profile_id); + }); +} + pub(super) fn describe_panic_payload(payload: &(dyn Any + Send)) -> String { if let Some(message) = payload.downcast_ref::<&str>() { (*message).to_string() diff --git a/src-tauri/src/cmd/profile_switch/workflow/state_machine.rs b/src-tauri/src/cmd/profile_switch/workflow/state_machine.rs index 5a177fea..e3c2b365 100644 --- a/src-tauri/src/cmd/profile_switch/workflow/state_machine.rs +++ b/src-tauri/src/cmd/profile_switch/workflow/state_machine.rs @@ -4,6 +4,7 @@ use crate::{ config::{Config, IProfiles, profiles::profiles_save_file_safe}, core::{CoreManager, handle, tray::Tray}, logging, + process::AsyncHandler, utils::logging::Type, }; use futures::FutureExt; @@ -316,6 +317,8 @@ impl SwitchStateMachine { Err(_) => CoreUpdateOutcome::Timeout, }; + self.ctx.release_locks(); + Ok(SwitchState::Finalize(outcome)) } @@ -334,12 +337,18 @@ impl SwitchStateMachine { "Configuration update succeeded, sequence: {}", self.ctx.sequence() ); - match time::timeout(CONFIG_APPLY_TIMEOUT, async { - Config::profiles().await.apply(); + let apply_result = time::timeout(CONFIG_APPLY_TIMEOUT, async { + AsyncHandler::spawn_blocking(|| { + futures::executor::block_on(async { + Config::profiles().await.apply(); + }); + }) + .await }) - .await - { - Ok(()) => {} + .await; + + match apply_result { + Ok(_) => {} Err(_) => { logging!( warn, @@ -366,64 +375,59 @@ impl SwitchStateMachine { ); } - match time::timeout(TRAY_UPDATE_TIMEOUT, Tray::global().update_tooltip()).await { - Ok(Ok(())) => {} - Ok(Err(err)) => { - logging!( - warn, - Type::Cmd, - "Failed to update tray tooltip asynchronously: {}", - err - ); - } - Err(_) => { - logging!( - warn, - Type::Cmd, - "Updating tray tooltip timed out after {:?}", - TRAY_UPDATE_TIMEOUT - ); - } + let update_tooltip = time::timeout(TRAY_UPDATE_TIMEOUT, async { + Tray::global().update_tooltip().await + }) + .await; + if update_tooltip.is_err() { + logging!( + warn, + Type::Cmd, + "Updating tray tooltip timed out after {:?}", + TRAY_UPDATE_TIMEOUT + ); + } else if let Ok(Err(err)) = update_tooltip { + logging!( + warn, + Type::Cmd, + "Failed to update tray tooltip asynchronously: {}", + err + ); } - match time::timeout(TRAY_UPDATE_TIMEOUT, Tray::global().update_menu()).await { - Ok(Ok(())) => {} - Ok(Err(err)) => { - logging!( - warn, - Type::Cmd, - "Failed to update tray menu asynchronously: {}", - err - ); - } - Err(_) => { - logging!( - warn, - Type::Cmd, - "Updating tray menu timed out after {:?}", - TRAY_UPDATE_TIMEOUT - ); - } + let update_menu = time::timeout(TRAY_UPDATE_TIMEOUT, async { + Tray::global().update_menu().await + }) + .await; + if update_menu.is_err() { + logging!( + warn, + Type::Cmd, + "Updating tray menu timed out after {:?}", + TRAY_UPDATE_TIMEOUT + ); + } else if let Ok(Err(err)) = update_menu { + logging!( + warn, + Type::Cmd, + "Failed to update tray menu asynchronously: {}", + err + ); } - match time::timeout(SAVE_PROFILES_TIMEOUT, profiles_save_file_safe()).await { - Ok(Ok(())) => {} - Ok(Err(err)) => { - logging!( - warn, - Type::Cmd, - "Failed to persist configuration file asynchronously: {}", - err - ); - } - Err(_) => { - logging!( - warn, - Type::Cmd, - "Persisting configuration file timed out after {:?}", - SAVE_PROFILES_TIMEOUT - ); - } + let save_future = AsyncHandler::spawn_blocking(|| { + futures::executor::block_on(async { profiles_save_file_safe().await }) + }); + if time::timeout(SAVE_PROFILES_TIMEOUT, save_future) + .await + .is_err() + { + logging!( + warn, + Type::Cmd, + "Persisting configuration file timed out after {:?}", + SAVE_PROFILES_TIMEOUT + ); } if let Some(current) = self.ctx.new_profile_for_event.clone() { @@ -620,6 +624,11 @@ impl SwitchContext { ), } } + + fn release_locks(&mut self) { + self.core_guard = None; + self.switch_scope = None; + } } enum SwitchState {