Skip to main content

meerkat_runtime/
user_interrupt.rs

1use std::sync::Arc;
2
3use meerkat_core::lifecycle::CoreExecutorInterruptHandle;
4use meerkat_core::types::SessionId;
5
6use crate::meerkat_machine::MeerkatMachine;
7use crate::runtime_state::RuntimeState;
8use crate::traits::RuntimeDriverError;
9
10impl MeerkatMachine {
11    pub async fn hard_cancel_current_run(
12        &self,
13        session_id: &SessionId,
14        reason: impl Into<String>,
15    ) -> Result<(), RuntimeDriverError> {
16        self.dispatch_user_interrupt(session_id, reason.into())
17            .await
18    }
19
20    // `user_interrupt` is mounted as a private child of `dispatch_session`, so
21    // this live-authority helper is visible only to the private admitted
22    // interrupt path and not to peer-admission siblings.
23    pub(super) async fn apply_user_interrupt_live_cancel(
24        &self,
25        session_id: &SessionId,
26        reason: String,
27    ) -> Result<(), RuntimeDriverError> {
28        let authority = UserInterruptAuthority::new();
29        self.hard_cancel_current_run_authorized(session_id, reason, authority)
30            .await
31    }
32
33    async fn hard_cancel_current_run_authorized(
34        &self,
35        session_id: &SessionId,
36        reason: String,
37        _authority: UserInterruptAuthority,
38    ) -> Result<(), RuntimeDriverError> {
39        let handle = self.interrupt_handle_for(session_id).await?;
40        handle.hard_cancel_current_run(reason).await.map_err(|err| {
41            RuntimeDriverError::Internal(format!("failed to hard cancel run: {err}"))
42        })
43    }
44
45    async fn interrupt_handle_for(
46        &self,
47        session_id: &SessionId,
48    ) -> Result<Arc<dyn CoreExecutorInterruptHandle>, RuntimeDriverError> {
49        let handle = {
50            let sessions = self.sessions.read().await;
51            let entry = sessions
52                .get(session_id)
53                .ok_or(RuntimeDriverError::NotReady {
54                    state: RuntimeState::Destroyed,
55                })?;
56            entry.interrupt_handle()
57        };
58
59        let Some(handle) = handle else {
60            let state = self
61                .existing_session_runtime_state(session_id)
62                .await
63                .unwrap_or(RuntimeState::Destroyed);
64            return Err(RuntimeDriverError::NotReady { state });
65        };
66
67        Ok(handle)
68    }
69}
70
71struct UserInterruptAuthority(());
72
73impl UserInterruptAuthority {
74    fn new() -> Self {
75        Self(())
76    }
77}