use std::sync::Arc;
use a2a_protocol_types::task::TaskId;
use super::super::ExecutorTurn;
use crate::store::TaskStore;
use crate::streaming::EventQueueManager;
use super::execute::CancellationTokens;
pub(super) struct CommitGuard {
task_id: TaskId,
queues: EventQueueManager,
tokens: CancellationTokens,
store: Arc<dyn TaskStore>,
key: Option<String>,
leased: bool,
turn: Option<Arc<ExecutorTurn>>,
armed: bool,
}
impl CommitGuard {
pub(super) fn new(
task_id: TaskId,
queues: EventQueueManager,
tokens: CancellationTokens,
store: Arc<dyn TaskStore>,
key: Option<String>,
) -> Self {
Self {
task_id,
queues,
tokens,
store,
key,
leased: false,
turn: None,
armed: true,
}
}
pub(super) const fn leased(&mut self) {
self.leased = true;
}
pub(super) fn registered(&mut self, turn: &Arc<ExecutorTurn>) {
self.turn = Some(Arc::clone(turn));
}
pub(super) const fn disarm(&mut self) {
self.armed = false;
}
}
impl Drop for CommitGuard {
fn drop(&mut self) {
if !self.armed {
return;
}
let task_id = self.task_id.clone();
let queues = self.queues.clone();
let tokens = Arc::clone(&self.tokens);
let store = Arc::clone(&self.store);
let key = self.key.take();
let leased = self.leased;
let turn = self.turn.take();
trace_warn!(
task_id = %task_id,
"send dropped before its executor started; releasing what it took"
);
tokio::spawn(async move {
if leased {
queues.destroy(&task_id).await;
}
if let Some(turn) = turn {
let mut map = tokens.write().await;
if map
.get(&task_id)
.is_some_and(|e| Arc::ptr_eq(&e.turn, &turn))
{
map.remove(&task_id);
}
}
if let Some(key) = key {
let _ = store.release_idempotency_key(&key).await;
}
});
}
}