refactor(#2441): move agent field from DAG onto Node; drop dedup
Agent was a single field on Dag/DagSpec, making a DAG structurally one-agent — a multi-agent op could only ever be N separate DAGs. Move it onto Node/NodeSpec (and the NodeView wire type), drop it from Dag/DagSpec (and DagView): a DAG can now span agents. - lifecycle lease keys on the node's agent, still globally exclusive per agent across all DAGs (Inner.leases unchanged in shape). A DAG holds one lease per distinct agent it touches; settle() frees each at DAG-terminal (per-agent-subgraph early release is a follow-up, only observable with multi-agent DAGs). - transient guard keyed (dag_id, agent); cancel-revert + Rebuilt events walk TerminalDag.agents. - submit-time dedup removed (a multi-agent DAG has no single agent to key on); every submit enqueues a fresh DAG. Whether dedup needs reintroducing is tracked in a follow-up sub-issue. - templates gain a node(agent, kind, deps) helper stamping the agent onto every node; meta templates stamp "hyperhive". Templates stay single-agent in this PR — behaviour is unchanged, only the representation + wire shape. Multi-agent DAG emission (restart/restart-all/ broad stop+start as one DAG) and the SetWanted-as-a-node change are follow-ups off #2439.
This commit is contained in:
parent
91607f3896
commit
2a59f2f5fc
7 changed files with 223 additions and 356 deletions
|
|
@ -5,33 +5,15 @@
|
|||
//! `hive_sh4re::jobs` (wire types belong to the shared crate) and are
|
||||
//! re-exported here for the queue's internal use.
|
||||
//!
|
||||
//! Two levels: the **DAG** is the unit of dedup / cancel /
|
||||
//! approval-resolution and the dashboard group; the **node** is the
|
||||
//! unit of scheduling / execution / build-log / step label. See
|
||||
//! `docs/coordinator.md::Job queue` for the full design.
|
||||
//! Two levels: the **DAG** is the unit of cancel / approval-resolution
|
||||
//! and the dashboard group; the **node** is the unit of scheduling /
|
||||
//! execution / build-log / step label, and carries its own `agent` (a
|
||||
//! DAG can span agents). See `docs/coordinator.md::Job queue` for the
|
||||
//! full design.
|
||||
|
||||
pub use hive_sh4re::jobs::{DagView, NodeId, NodeView, PermPayload, Source, State, Template};
|
||||
use serde::Serialize;
|
||||
|
||||
/// Dedup compares the perm *type*, not the value — a tool-groups
|
||||
/// change and a capabilities change for the same agent are distinct
|
||||
/// operations that must not collapse.
|
||||
pub(super) fn perm_payload_same_type(a: Option<&PermPayload>, b: Option<&PermPayload>) -> bool {
|
||||
matches!(
|
||||
(a, b),
|
||||
(
|
||||
Some(PermPayload::ToolGroups { .. }),
|
||||
Some(PermPayload::ToolGroups { .. })
|
||||
) | (
|
||||
Some(PermPayload::Capabilities { .. }),
|
||||
Some(PermPayload::Capabilities { .. })
|
||||
) | (
|
||||
Some(PermPayload::Combined { .. }),
|
||||
Some(PermPayload::Combined { .. })
|
||||
) | (None, None)
|
||||
)
|
||||
}
|
||||
|
||||
/// When a dependency edge is considered satisfied.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
|
|
@ -203,6 +185,11 @@ impl NodeKind {
|
|||
#[derive(Debug, Clone)]
|
||||
pub struct Node {
|
||||
pub id: NodeId,
|
||||
/// The agent this node's work targets. Per-node so a single DAG can
|
||||
/// span agents (e.g. a hive-wide restart); the lifecycle lease is
|
||||
/// acquired against *this* agent (still globally exclusive per agent
|
||||
/// across all DAGs). `"hyperhive"` for meta-level nodes.
|
||||
pub agent: String,
|
||||
pub kind: NodeKind,
|
||||
pub deps: Vec<Dep>,
|
||||
pub state: State,
|
||||
|
|
@ -221,19 +208,23 @@ pub struct Node {
|
|||
/// Submit-time spec for one node.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct NodeSpec {
|
||||
/// The agent this node targets (see [`Node::agent`]). Built by the
|
||||
/// `templates.rs` `node` helper, which stamps the template's agent
|
||||
/// onto every node.
|
||||
pub agent: String,
|
||||
pub kind: NodeKind,
|
||||
pub deps: Vec<Dep>,
|
||||
}
|
||||
|
||||
/// Submit-time spec for a whole DAG. Built by `templates.rs`; validated
|
||||
/// (cycle rejection) and dedup'd by `JobQueue::submit`.
|
||||
/// (cycle rejection) by `JobQueue::submit`. No DAG-level `agent` — every
|
||||
/// node carries its own (a DAG can span agents), and the queue derives
|
||||
/// per-agent leasing from [`NodeSpec::agent`].
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DagSpec {
|
||||
pub template: Template,
|
||||
/// Primary target agent, or `"hyperhive"` for meta-level DAGs.
|
||||
pub agent: String,
|
||||
pub source: Source,
|
||||
/// Free-form "why"; dedup appends "also requested by …" lines.
|
||||
/// Free-form "why".
|
||||
pub reason: String,
|
||||
/// Cascade grouping (meta-update / sweep children).
|
||||
pub parent_id: Option<u64>,
|
||||
|
|
@ -250,12 +241,13 @@ pub struct DagSpec {
|
|||
pub nodes: Vec<NodeSpec>,
|
||||
}
|
||||
|
||||
/// A live DAG in the queue.
|
||||
/// A live DAG in the queue. No DAG-level `agent`: agent is per-[`Node`],
|
||||
/// so a DAG can span agents. Per-agent leasing is derived from the
|
||||
/// nodes' agents.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Dag {
|
||||
pub id: u64,
|
||||
pub template: Template,
|
||||
pub agent: String,
|
||||
pub source: Source,
|
||||
pub reason: String,
|
||||
pub parent_id: Option<u64>,
|
||||
|
|
@ -319,6 +311,19 @@ impl Dag {
|
|||
pub fn node_mut(&mut self, id: NodeId) -> Option<&mut Node> {
|
||||
self.nodes.iter_mut().find(|n| n.id == id)
|
||||
}
|
||||
|
||||
/// Distinct agents this DAG's nodes target, in first-seen order.
|
||||
/// Used for per-agent lease release and the terminal cancel-revert —
|
||||
/// a single-agent DAG yields one, a multi-agent DAG yields several.
|
||||
pub fn agents(&self) -> Vec<String> {
|
||||
let mut seen: Vec<String> = Vec::new();
|
||||
for n in &self.nodes {
|
||||
if !seen.iter().any(|a| a == &n.agent) {
|
||||
seen.push(n.agent.clone());
|
||||
}
|
||||
}
|
||||
seen
|
||||
}
|
||||
}
|
||||
|
||||
impl Dag {
|
||||
|
|
@ -331,7 +336,6 @@ impl Dag {
|
|||
};
|
||||
DagView {
|
||||
id: self.id,
|
||||
agent: self.agent.clone(),
|
||||
kind: self.template,
|
||||
state: self.rollup(),
|
||||
source: self.source,
|
||||
|
|
@ -348,6 +352,7 @@ impl Dag {
|
|||
.iter()
|
||||
.map(|n| NodeView {
|
||||
id: n.id,
|
||||
agent: n.agent.clone(),
|
||||
kind: n.kind.as_str().to_owned(),
|
||||
deps: n.deps.iter().map(|d| d.on).collect(),
|
||||
state: n.state,
|
||||
|
|
|
|||
Loading…
Reference in a new issue