agent_engine/daemon/
lifecycle.rs1use std::sync::Arc;
5use std::time::Duration;
6
7use super::DaemonState;
8use crate::session::{EndReason, SessionCommand};
9
10pub const SESSION_END_BUDGET: Duration = Duration::from_secs(crate::session::budgets::TEARDOWN_TIMEOUT_SECS);
13pub const FORCE_BUDGET: Duration = Duration::from_millis(500);
15
16pub async fn shutdown_all(state: &Arc<DaemonState>, force: bool) {
17 let sessions = state.live_sessions();
18 let n = sessions.len();
19 tracing::info!(sessions = n, force, "daemon: ending sessions");
20 let budget = if force { FORCE_BUDGET } else { SESSION_END_BUDGET };
21 let ends = sessions.iter().map(|h| async move {
22 let _ = h.send(SessionCommand::End { reason: EndReason::HostShutdown }).await;
23 h.closed().await;
24 });
25 if tokio::time::timeout(budget, futures::future::join_all(ends)).await.is_err() {
26 tracing::warn!(budget = ?budget, "daemon: session shutdown budget exceeded; continuing");
27 }
28 for h in &sessions {
29 state.host.remove_session(&h.id);
30 }
31
32 let ext = Arc::clone(state.host.ext_manager());
33 let ext_shutdown = async move { ext.write().await.shutdown_all().await };
34 if tokio::time::timeout(Duration::from_secs(5), ext_shutdown).await.is_err() {
35 tracing::warn!("daemon: extension shutdown budget exceeded");
36 }
37 state.host.flush_logs();
38}