feat(infra): temp IdeA généralisé à tous les agents + purge du store managed-tmp au shutdown d'IdeA — #200 (QA verte)
This commit is contained in:
@ -499,7 +499,7 @@ async fn app_exit_work_guard_state(
|
||||
///
|
||||
/// The order intentionally mirrors the historical inline `CloseRequested` hook:
|
||||
/// snapshot windows, snapshot `agent_was_running`, kill PTYs, stop model servers,
|
||||
/// stop the embedded server, then close secondary webview windows.
|
||||
/// stop the embedded server, purge managed temp, then close secondary webview windows.
|
||||
pub fn shutdown_app_after_confirm(handle: &tauri::AppHandle) {
|
||||
if let Some(state) = handle.try_state::<AppState>() {
|
||||
let open_windows = snapshot_open_webview_windows(handle);
|
||||
@ -508,6 +508,7 @@ pub fn shutdown_app_after_confirm(handle: &tauri::AppHandle) {
|
||||
let snapshot = std::sync::Arc::clone(&state.snapshot_running_agents);
|
||||
let model_servers = std::sync::Arc::clone(&state.ensure_local_model_server);
|
||||
let embedded_server = std::sync::Arc::clone(&state.embedded_server);
|
||||
let purge_managed_temp = std::sync::Arc::clone(&state.purge_managed_temp);
|
||||
let open_projects = state.open_project_ids();
|
||||
let handles = state.terminal_sessions.handles();
|
||||
tauri::async_runtime::block_on(async move {
|
||||
@ -526,12 +527,19 @@ pub fn shutdown_app_after_confirm(handle: &tauri::AppHandle) {
|
||||
}
|
||||
let _ = model_servers.stop_on_app_exit().await;
|
||||
let _ = embedded_server.stop().await;
|
||||
purge_managed_temp_for_shutdown(&purge_managed_temp).await;
|
||||
});
|
||||
}
|
||||
|
||||
close_non_main_webview_windows(handle);
|
||||
}
|
||||
|
||||
async fn purge_managed_temp_for_shutdown(purge: &application::PurgeManagedTemp) {
|
||||
if let Err(err) = purge.execute().await {
|
||||
application::diag!("[managed-temp] shutdown purge failed: {err}");
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn confirm_next_main_window_close() {
|
||||
EXIT_GUARD_CONFIRMED.store(true, Ordering::SeqCst);
|
||||
}
|
||||
@ -848,12 +856,21 @@ mod tests {
|
||||
use super::{
|
||||
apply_main_close_decision, confirm_next_main_window_close, consume_exit_guard_confirmation,
|
||||
decide_main_close_action, persisted_view_identity_from_label,
|
||||
persisted_window_identity_from_label, should_install_exit_guard, MainCloseAction,
|
||||
persisted_window_identity_from_label, purge_managed_temp_for_shutdown,
|
||||
should_install_exit_guard, MainCloseAction,
|
||||
};
|
||||
use super::{should_close_with_main_window, PersistedWindowKind};
|
||||
use application::AppExitWorkGuardState;
|
||||
use application::{AppExitWorkGuardState, PurgeManagedTemp};
|
||||
use async_trait::async_trait;
|
||||
use domain::ports::ManagedTempStore;
|
||||
use domain::{
|
||||
ManagedTempAllocation, ManagedTempError, ManagedTempGcReport, ManagedTempHandle,
|
||||
ManagedTempLease,
|
||||
};
|
||||
use serde_json::json;
|
||||
use std::cell::Cell;
|
||||
use std::sync::atomic::{AtomicBool, Ordering as AtomicOrdering};
|
||||
use std::sync::Arc;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
use tauri::test::{get_ipc_response, mock_builder, mock_context, noop_assets, INVOKE_KEY};
|
||||
|
||||
@ -865,6 +882,57 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
struct FailingPurgeStore {
|
||||
called: Arc<AtomicBool>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl ManagedTempStore for FailingPurgeStore {
|
||||
async fn allocate(
|
||||
&self,
|
||||
_allocation: ManagedTempAllocation,
|
||||
) -> Result<ManagedTempLease, ManagedTempError> {
|
||||
Err(ManagedTempError::Store("unused".to_owned()))
|
||||
}
|
||||
|
||||
async fn resolve(
|
||||
&self,
|
||||
_handle: &ManagedTempHandle,
|
||||
_now_ms: u64,
|
||||
) -> Result<ManagedTempLease, ManagedTempError> {
|
||||
Err(ManagedTempError::Store("unused".to_owned()))
|
||||
}
|
||||
|
||||
async fn release(
|
||||
&self,
|
||||
_handle: &ManagedTempHandle,
|
||||
_now_ms: u64,
|
||||
) -> Result<ManagedTempLease, ManagedTempError> {
|
||||
Err(ManagedTempError::Store("unused".to_owned()))
|
||||
}
|
||||
|
||||
async fn gc(&self, _now_ms: u64) -> Result<ManagedTempGcReport, ManagedTempError> {
|
||||
Err(ManagedTempError::Store("unused".to_owned()))
|
||||
}
|
||||
|
||||
async fn purge_all(&self) -> Result<ManagedTempGcReport, ManagedTempError> {
|
||||
self.called.store(true, AtomicOrdering::SeqCst);
|
||||
Err(ManagedTempError::Store("partial purge failed".to_owned()))
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn shutdown_managed_temp_purge_is_attempted_and_non_blocking_on_error() {
|
||||
let called = Arc::new(AtomicBool::new(false));
|
||||
let purge = PurgeManagedTemp::new(Arc::new(FailingPurgeStore {
|
||||
called: Arc::clone(&called),
|
||||
}));
|
||||
|
||||
purge_managed_temp_for_shutdown(&purge).await;
|
||||
|
||||
assert!(called.load(AtomicOrdering::SeqCst));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn main_close_with_work_prevents_and_notifies_before_shutdown() {
|
||||
assert_eq!(
|
||||
|
||||
@ -232,6 +232,12 @@ mod tests {
|
||||
async fn gc(&self, _now_ms: u64) -> Result<ManagedTempGcReport, ManagedTempError> {
|
||||
Ok(ManagedTempGcReport { deleted: 1 })
|
||||
}
|
||||
|
||||
async fn purge_all(&self) -> Result<ManagedTempGcReport, ManagedTempError> {
|
||||
let deleted = self.leases.lock().unwrap().len();
|
||||
self.leases.lock().unwrap().clear();
|
||||
Ok(ManagedTempGcReport { deleted })
|
||||
}
|
||||
}
|
||||
|
||||
fn project() -> Project {
|
||||
|
||||
Reference in New Issue
Block a user