refactor(#2908): cancel a node, not a DAG
`JobQueue::cancel(dag_id)` resolved the id to a `NodeKind::Dag` container
and cancelled that. But the container lookup was the only DAG-specific
part — everything that makes cancel work already lives in the scheduler:
`cancel_node` marks the node `Cancelled` and cascades to its pending
descendants, sparing any node whose edge accepts `Cancelled` (which is
what keeps a dropped approval DAG from dangling its row).
So `cancel` now takes any node id. A group root cancels the whole group,
which is what the dashboard's button does today and why nothing about
its behaviour changes: a DAG id *is* its root node's id. An interior
node cancels just that branch — a capability the DAG-scoped version
could not express, covered by the new test (a hive-wide restart drops
one agent's subgraph while the other keeps running).
`QueueInner::node_by_id` replaces `container()` here: same search, same
cost, without asserting the node is a DAG container. `container()` stays
for `first_error` and the append-subgraph guard, which are genuinely
DAG-scoped.
No wire change. The route is `POST /api/rebuild-queue/{id}/cancel` with
a `u64` path param — same type, same route, and the client keeps sending
the same number. Only the param's documented meaning moves from "DAG id"
to "node id".
Checked with clippy (`--all-targets -D warnings`), `cargo test -p
hive-c0re` (322 passed) and `nix fmt`. No option surface touched, so no
nix-eval gate.
This commit is contained in:
parent
4835ca8c91
commit
eb557ee3c1
3 changed files with 60 additions and 6 deletions
|
|
@ -345,12 +345,16 @@ impl JobQueue {
|
|||
/// say) is cancelled along with everything else — there is nothing to converge
|
||||
/// when no node ever ran. Only a node that named `Cancelled` survives, and it
|
||||
/// survives because it asked to.
|
||||
pub fn cancel(&self, dag_id: u64) -> bool {
|
||||
/// `id` names **any node**, not specifically a DAG. Cancelling a group root
|
||||
/// drops that whole group (the cascade is the scheduler's), which is what
|
||||
/// the dashboard's whole-DAG cancel does; cancelling an interior node drops
|
||||
/// just that branch. Nothing here knows about DAGs.
|
||||
pub fn cancel(&self, id: u64) -> bool {
|
||||
let mut inner = self.lock();
|
||||
let Some(container) = inner.container(dag_id) else {
|
||||
let Some(node) = inner.node_by_id(id) else {
|
||||
return false;
|
||||
};
|
||||
if !inner.sched.cancel_node(container) {
|
||||
if !inner.sched.cancel_node(node) {
|
||||
return false;
|
||||
}
|
||||
drop(inner);
|
||||
|
|
@ -460,6 +464,17 @@ impl QueueInner {
|
|||
|
||||
/// The container node of `dag_id` — the `NodeKind::Dag` root whose id equals
|
||||
/// `dag_id`. `NodeId` is un-fabricable from a raw `u64`, so this is a search.
|
||||
/// Resolve a raw wire `u64` to a graph [`NodeId`], whatever kind of node it
|
||||
/// names. `NodeId` is un-fabricable from a `u64`, so this is a search —
|
||||
/// same cost as [`QueueInner::container`], without asserting the node is a
|
||||
/// DAG container.
|
||||
fn node_by_id(&self, id: u64) -> Option<NodeId> {
|
||||
self.sched
|
||||
.graph()
|
||||
.nodes()
|
||||
.find_map(|n| (n.id.get() == id).then_some(n.id))
|
||||
}
|
||||
|
||||
fn container(&self, dag_id: u64) -> Option<NodeId> {
|
||||
self.sched.graph().nodes().find_map(|n| {
|
||||
(n.parent.is_none()
|
||||
|
|
|
|||
Loading…
Reference in a new issue