use std::sync::Arc;
use tokio::sync::oneshot;
use super::PendingJoins;
use crate::{
core::registry::{
Registry,
protocol::{CancelDecision, CancelReply, RemoveReply},
state::{EntryState, Handle, Inner},
},
events::{Event, EventKind},
identity::TaskId,
};
struct CancelAction {
decision: CancelDecision,
handle: Option<Handle>,
}
impl Registry {
pub(in crate::core::registry) async fn remove_task(
&self,
id: TaskId,
reply: oneshot::Sender<RemoveReply>,
) {
if let Some((_label, handle, completion)) = self.claim_task(id).await {
handle.cancel.cancel();
let _ = reply.send(Ok(true));
self.spawn_join_report(id, handle, Some(self.grace), completion);
} else {
let _ = reply.send(Ok(false));
}
}
pub(in crate::core::registry) async fn remove_task_by_label(
&self,
label: Arc<str>,
reply: oneshot::Sender<RemoveReply>,
) {
let resolved = {
let mut st = self.state.write().await;
st.by_label.get(label.as_ref()).copied().map(|id| {
let claimed = Self::claim_registered(&mut st, &self.pending_joins, id)
.map(|(_entry_label, handle, completion)| (handle, completion));
(id, claimed)
})
};
let Some((id, claimed)) = resolved else {
let _ = reply.send(Ok(false));
return;
};
self.bus.publish_lazy(|| {
Event::new(EventKind::TaskRemoveRequested)
.with_task(Arc::clone(&label))
.with_id(id)
});
if let Some((handle, completion)) = claimed {
handle.cancel.cancel();
let _ = reply.send(Ok(true));
self.spawn_join_report(id, handle, Some(self.grace), completion);
} else {
let _ = reply.send(Ok(false));
}
}
pub(in crate::core::registry) async fn cancel_task(
&self,
id: TaskId,
reply: oneshot::Sender<CancelReply>,
) {
let (found, action) = {
let mut st = self.state.write().await;
if !st.tasks.contains_key(&id) {
(false, None)
} else {
(true, Self::cancel_action(&mut st, &self.pending_joins, id))
}
};
if found {
self.bus.publish_lazy(|| {
Event::new(EventKind::TaskRemoveRequested)
.with_id(id)
.with_reason("manual_cancel")
});
}
self.resolve_cancel_action(action, reply);
}
pub(in crate::core::registry) async fn cancel_task_by_label(
&self,
label: Arc<str>,
reply: oneshot::Sender<CancelReply>,
) {
let resolved = {
let mut st = self.state.write().await;
st.by_label.get(label.as_ref()).copied().map(|id| {
let action = Self::cancel_action(&mut st, &self.pending_joins, id);
(id, action)
})
};
let Some((id, action)) = resolved else {
let _ = reply.send(Ok(None));
return;
};
self.bus.publish_lazy(|| {
Event::new(EventKind::TaskRemoveRequested)
.with_task(Arc::clone(&label))
.with_id(id)
.with_reason("manual_cancel")
});
self.resolve_cancel_action(action, reply);
}
fn cancel_action(
st: &mut Inner,
pending_joins: &PendingJoins,
id: TaskId,
) -> Option<CancelAction> {
let existing_completion = {
let entry = st.tasks.get(&id)?;
match &entry.state {
EntryState::Registered(_) => None,
EntryState::Removing { completion } => Some(completion.clone()),
}
};
if let Some(completion) = existing_completion {
return Some(CancelAction {
decision: CancelDecision {
id,
claimed: false,
completion,
},
handle: None,
});
}
let (_label, handle, completion) = Self::claim_registered(st, pending_joins, id)
.expect("a registered entry must be claimable while state is locked");
Some(CancelAction {
decision: CancelDecision {
id,
claimed: true,
completion,
},
handle: Some(handle),
})
}
fn resolve_cancel_action(
&self,
action: Option<CancelAction>,
reply: oneshot::Sender<CancelReply>,
) {
let Some(CancelAction { decision, handle }) = action else {
let _ = reply.send(Ok(None));
return;
};
if let Some(handle) = handle {
handle.cancel.cancel();
let completion = decision.completion.clone();
let id = decision.id;
let _ = reply.send(Ok(Some(decision)));
self.spawn_join_report(id, handle, Some(self.grace), completion);
} else {
let _ = reply.send(Ok(Some(decision)));
}
}
}