refactor(#2591): model a DAG as a container node — grouping side-tables become graph walks
This commit is contained in:
parent
8834161fb9
commit
a78280feed
4 changed files with 362 additions and 324 deletions
|
|
@ -100,76 +100,69 @@ pub(super) async fn run_node(coord: &Arc<Coordinator>, claim: &Claim) -> Result<
|
|||
NodeKind::WritePermFile => run_write_perm_file(coord, claim, &ctx).await,
|
||||
NodeKind::ApprovalDeploy => run_approval_deploy(coord, claim).await,
|
||||
NodeKind::SetWanted { up } => run_set_wanted(coord, claim, *up),
|
||||
NodeKind::ResolveApproval => run_resolve_approval(coord, claim).await,
|
||||
NodeKind::EmitRebuilt => Ok(run_emit_rebuilt(coord, claim)),
|
||||
NodeKind::RevertIntent => run_revert_intent(coord, claim).await,
|
||||
// Pure grouping container — no work; completing it lets it reach
|
||||
// `Finishing` so its child template nodes start. The DAG's terminal
|
||||
// hook fires when the container itself rolls up terminal.
|
||||
// hook fires (inline, via `run_terminal_hook`) when the container itself
|
||||
// rolls up terminal — not as a scheduled node.
|
||||
NodeKind::Dag { .. } => Ok(NodeOutput::default()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Terminal hook (approval DAGs — spawn / opaque deploy): resolve the DAG's
|
||||
/// approval row from its rolled-up outcome. Its own graph node, weak-dep on the
|
||||
/// DAG tails, so it runs once everything has settled (any outcome, incl. a
|
||||
/// cancel before starting — the fallback that resolves a queued-then-cancelled
|
||||
/// approval whose node never ran). Always succeeds — a hook failure is logged
|
||||
/// inside, not surfaced as a node failure.
|
||||
async fn run_resolve_approval(coord: &Arc<Coordinator>, claim: &Claim) -> Result<NodeOutput> {
|
||||
if let Some(terminal) = coord.job_queue.terminal_summary(claim.dag_id) {
|
||||
crate::actions::resolve_approval_dag(coord, &terminal).await;
|
||||
/// Run a settled DAG's inline terminal hook, dispatched off its rolled-up
|
||||
/// summary — the container-terminal replacement for the old per-DAG hook node.
|
||||
/// Always best-effort: a hook failure is logged inside, never surfaced.
|
||||
pub(super) async fn run_terminal_hook(coord: &Arc<Coordinator>, terminal: &super::TerminalDag) {
|
||||
match super::terminal_hook(terminal.template, terminal.approval_id) {
|
||||
Some(super::HookKind::ResolveApproval) => {
|
||||
crate::actions::resolve_approval_dag(coord, terminal).await;
|
||||
}
|
||||
Some(super::HookKind::EmitRebuilt) => emit_rebuilt(coord, terminal),
|
||||
Some(super::HookKind::RevertIntent) => revert_intent(coord, terminal).await,
|
||||
None => {}
|
||||
}
|
||||
Ok(NodeOutput::default())
|
||||
}
|
||||
|
||||
/// Terminal hook (rebuild / perm-change DAGs): emit one `Rebuilt` manager event
|
||||
/// per targeted agent — `ok` on `Done`, `!ok` on `Failed`, none on cancel.
|
||||
fn run_emit_rebuilt(coord: &Arc<Coordinator>, claim: &Claim) -> NodeOutput {
|
||||
if let Some(terminal) = coord.job_queue.terminal_summary(claim.dag_id) {
|
||||
for agent in &terminal.agents {
|
||||
match terminal.state {
|
||||
State::Done => coord.notify_manager(&hive_sh4re::HelperEvent::Rebuilt {
|
||||
agent: agent.clone(),
|
||||
ok: true,
|
||||
note: None,
|
||||
sha: None,
|
||||
tag: None,
|
||||
}),
|
||||
State::Failed => coord.notify_manager(&hive_sh4re::HelperEvent::Rebuilt {
|
||||
agent: agent.clone(),
|
||||
ok: false,
|
||||
note: terminal.error.clone(),
|
||||
sha: None,
|
||||
tag: None,
|
||||
}),
|
||||
_ => {}
|
||||
}
|
||||
/// Rebuild / perm-change hook: emit one `Rebuilt` manager event per targeted
|
||||
/// agent — `ok` on `Done`, `!ok` on `Failed`, none on cancel.
|
||||
fn emit_rebuilt(coord: &Arc<Coordinator>, terminal: &super::TerminalDag) {
|
||||
for agent in &terminal.agents {
|
||||
match terminal.state {
|
||||
State::Done => coord.notify_manager(&hive_sh4re::HelperEvent::Rebuilt {
|
||||
agent: agent.clone(),
|
||||
ok: true,
|
||||
note: None,
|
||||
sha: None,
|
||||
tag: None,
|
||||
}),
|
||||
State::Failed => coord.notify_manager(&hive_sh4re::HelperEvent::Rebuilt {
|
||||
agent: agent.clone(),
|
||||
ok: false,
|
||||
note: terminal.error.clone(),
|
||||
sha: None,
|
||||
tag: None,
|
||||
}),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
NodeOutput::default()
|
||||
}
|
||||
|
||||
/// Terminal hook (power-op DAGs): on a *cancelled* DAG, revert each targeted
|
||||
/// agent's `wanted` intent to its observed state — the operator's cancel means
|
||||
/// "don't do it", so the intent snaps back instead of the flip executing as a
|
||||
/// surprise side effect of some later reconcile. Noop on any non-cancelled
|
||||
/// outcome. Always succeeds — a revert failure is logged, not surfaced.
|
||||
async fn run_revert_intent(coord: &Arc<Coordinator>, claim: &Claim) -> Result<NodeOutput> {
|
||||
if let Some(terminal) = coord.job_queue.terminal_summary(claim.dag_id)
|
||||
&& terminal.state == State::Cancelled
|
||||
{
|
||||
for agent in &terminal.agents {
|
||||
let running = crate::lifecycle::is_running(agent).await;
|
||||
if let Err(e) = coord
|
||||
.power
|
||||
.set(agent, crate::power::Wanted::from_running(running))
|
||||
{
|
||||
tracing::warn!(%agent, error = ?e, "agent_power: cancel revert failed");
|
||||
}
|
||||
/// Power-op hook: on a *cancelled* DAG, revert each targeted agent's `wanted`
|
||||
/// intent to its observed state — the operator's cancel means "don't do it", so
|
||||
/// the intent snaps back instead of the flip executing as a surprise side effect
|
||||
/// of some later reconcile. Noop on any non-cancelled outcome.
|
||||
async fn revert_intent(coord: &Arc<Coordinator>, terminal: &super::TerminalDag) {
|
||||
if terminal.state != State::Cancelled {
|
||||
return;
|
||||
}
|
||||
for agent in &terminal.agents {
|
||||
let running = crate::lifecycle::is_running(agent).await;
|
||||
if let Err(e) = coord
|
||||
.power
|
||||
.set(agent, crate::power::Wanted::from_running(running))
|
||||
{
|
||||
tracing::warn!(%agent, error = ?e, "agent_power: cancel revert failed");
|
||||
}
|
||||
}
|
||||
Ok(NodeOutput::default())
|
||||
}
|
||||
|
||||
/// Write the agent's durable power intent — the DAG-node form of the old
|
||||
|
|
|
|||
Loading…
Reference in a new issue