use crate::value::{VmJoinHandle, VmTaskHandle, VmValue};
pub(super) type VmTaskJoinResult =
Result<Result<(VmValue, String), crate::value::VmError>, tokio::task::JoinError>;
pub(super) fn finish_task_join(
joined: VmTaskJoinResult,
task_id: String,
runtimes: crate::agent_lifecycle_cleanup::CleanupRuntimes,
) -> VmTaskJoinResult {
if !matches!(&joined, Ok(Ok(_))) {
schedule_task_cleanup(task_id, runtimes);
}
joined
}
pub(crate) fn abort_task_detached(
task: VmTaskHandle,
runtimes: crate::agent_lifecycle_cleanup::CleanupRuntimes,
) {
let task_id = task.wait_task_id.clone();
if task.handle.is_finished() {
schedule_task_cleanup(task_id, runtimes);
return;
}
task.cancel_token
.store(true, std::sync::atomic::Ordering::SeqCst);
task.handle.abort();
schedule_task_cleanup_after(task_id, runtimes, async move {
let _ = task.handle.await;
});
}
pub(crate) fn schedule_task_cleanup(
task_id: String,
runtimes: crate::agent_lifecycle_cleanup::CleanupRuntimes,
) {
schedule_task_cleanup_after(task_id, runtimes, std::future::ready(()));
}
fn schedule_task_cleanup_after<F>(
task_id: String,
runtimes: crate::agent_lifecycle_cleanup::CleanupRuntimes,
before_cleanup: F,
) where
F: std::future::Future<Output = ()> + Send + 'static,
{
crate::vm::subtask::spawn_lifecycle_cleanup(async move {
before_cleanup.await;
crate::agent_lifecycle_cleanup::schedule(task_id, runtimes);
});
}
pub(super) async fn abort_task_and_wait(
mut task: VmTaskHandle,
execution_id: &str,
) -> Result<(), crate::value::VmError> {
let task_id = task.wait_task_id.clone();
task.cancel_token
.store(true, std::sync::atomic::Ordering::SeqCst);
abort_join_and_wait(&mut task.handle).await;
crate::llm::agent_session_host::cancellation::abandon_task_sessions(execution_id, &task_id)
.await
}
pub(super) async fn abort_join_and_wait(handle: &mut VmJoinHandle) {
handle.abort();
let _ = handle.await;
}
pub(super) struct AwaitingTask {
task: Option<VmTaskHandle>,
runtimes: crate::agent_lifecycle_cleanup::CleanupRuntimes,
}
impl AwaitingTask {
pub(super) fn new(
task: VmTaskHandle,
runtimes: crate::agent_lifecycle_cleanup::CleanupRuntimes,
) -> Self {
Self {
task: Some(task),
runtimes,
}
}
pub(super) async fn join(mut self) -> VmTaskJoinResult {
let joined = (&mut self.task.as_mut().expect("awaiting task present").handle).await;
let task = self.task.take().expect("awaiting task present after join");
finish_task_join(joined, task.wait_task_id, self.runtimes.clone())
}
}
impl Drop for AwaitingTask {
fn drop(&mut self) {
if let Some(task) = self.task.take() {
abort_task_detached(task, self.runtimes.clone());
}
}
}
#[cfg(test)]
#[path = "task_cleanup_tests.rs"]
mod tests;
pub(super) enum StepPreHookAction {
Allow(Vec<VmValue>),
Deny(String),
}