jobq: templates swallow the DagSpec layer
DagSpec described the graph the templates were about to build, one layer below the templates themselves. Per #2972 the templates should be that unit, so the spec type is gone and every declarer writes onto the job builder directly. - delete DagSpec<F> and its hand-written Debug impl - submit(source, reason, declare: impl FnOnce(&Job)) replaces the pre-built-spec signature; submit_and_emit follows - all six templates take &Job; the Source is now the caller's to pass, which spawn and approval_deploy previously hardcoded while the other four did not - power_dag dissolves into stop_nodes/start_nodes/restart_nodes, which borrow their targets instead of owning them 315 tests pass unchanged.
This commit is contained in:
parent
96ef592fee
commit
6899f574f6
7 changed files with 347 additions and 550 deletions
|
|
@ -24,18 +24,23 @@
|
|||
|
||||
use std::sync::Arc;
|
||||
|
||||
use super::model::{DagSpec, NodeKind};
|
||||
use super::model::NodeKind;
|
||||
use super::resource::Resource;
|
||||
use super::templates::{RebuildOpts, rebuild_nodes};
|
||||
use super::{Job, Source, templates};
|
||||
use crate::coordinator::Coordinator;
|
||||
use crate::lifecycle;
|
||||
|
||||
fn submit_and_emit<F: FnOnce(&Job)>(coord: &Arc<Coordinator>, spec: super::DagSpec<F>) -> u64 {
|
||||
fn submit_and_emit(
|
||||
coord: &Arc<Coordinator>,
|
||||
source: Source,
|
||||
reason: String,
|
||||
declare: impl FnOnce(&Job),
|
||||
) -> u64 {
|
||||
let id = coord
|
||||
.job_queue
|
||||
.submit(spec)
|
||||
.expect("template-built dag specs are acyclic");
|
||||
.submit(source, reason, declare)
|
||||
.expect("template-declared shapes are acyclic");
|
||||
coord.emit_rebuild_queue_snapshot();
|
||||
id
|
||||
}
|
||||
|
|
@ -44,7 +49,9 @@ fn submit_and_emit<F: FnOnce(&Job)>(coord: &Arc<Coordinator>, spec: super::DagSp
|
|||
/// meta input — the meta-update cascade grows its own rebuild subgraphs
|
||||
/// in-DAG instead of going through this surface).
|
||||
pub fn rebuild(coord: &Arc<Coordinator>, agent: &str, source: Source, reason: String) -> u64 {
|
||||
submit_and_emit(coord, templates::rebuild(agent, source, reason, true))
|
||||
submit_and_emit(coord, source, reason, |b| {
|
||||
templates::rebuild(b, agent, true);
|
||||
})
|
||||
}
|
||||
|
||||
// ---- dynamic power-op DAG assembly ----------------------------------------
|
||||
|
|
@ -185,44 +192,24 @@ fn restart_chain(b: &Job, agent: &str, graceful: bool, running: bool) {
|
|||
}
|
||||
}
|
||||
|
||||
/// Wrap the per-agent subgraphs in a `DagSpec`. No tail node: a power op's
|
||||
/// effect is its nodes (`SetWanted` + `Reconcile`), with nothing left to do once
|
||||
/// they settle.
|
||||
///
|
||||
/// There is no concatenation step: every chain declares into the same builder
|
||||
/// and each keeps its own root, so the per-agent subgraphs are independent and
|
||||
/// run concurrently, each on its own lease. Rebasing one subgraph's indices
|
||||
/// onto another's used to be a function.
|
||||
fn power_dag<F: FnOnce(&Job)>(source: Source, reason: String, declare: F) -> DagSpec<F> {
|
||||
DagSpec {
|
||||
source,
|
||||
reason,
|
||||
declare,
|
||||
}
|
||||
}
|
||||
|
||||
// The `*_spec` builders below are the PURE core the async `*_many` fns call
|
||||
// The `*_nodes` declarers below are the PURE core the async `*_many` fns call
|
||||
// after reading live state — they take the per-agent running (and stale)
|
||||
// flags explicitly, so unit tests exercise the online/offline shapes without
|
||||
// a live container. `*_many` = gather state + call `*_spec` + submit.
|
||||
// a live container. `*_many` = gather state + declare + submit.
|
||||
//
|
||||
// A power op has no tail node: its effect is its nodes (`SetWanted` +
|
||||
// `Reconcile`), with nothing left to do once they settle.
|
||||
//
|
||||
// There is no concatenation step either: every chain declares into the same
|
||||
// builder and each keeps its own root, so the per-agent subgraphs are
|
||||
// independent and run concurrently, each on its own lease. Rebasing one
|
||||
// subgraph's indices onto another's used to be a function.
|
||||
|
||||
/// Assemble the stop DAG from explicit `(agent, running)` targets.
|
||||
pub(crate) fn stop_spec(
|
||||
targets: &[(String, bool)],
|
||||
graceful: bool,
|
||||
source: Source,
|
||||
reason: String,
|
||||
) -> DagSpec<impl FnOnce(&Job) + use<>> {
|
||||
let targets = targets.to_vec();
|
||||
power_dag(
|
||||
source,
|
||||
reason,
|
||||
Box::new(move |b: &Job| {
|
||||
for (agent, running) in targets {
|
||||
stop_chain(b, &agent, graceful, running);
|
||||
}
|
||||
}),
|
||||
)
|
||||
/// Declare the stop DAG from explicit `(agent, running)` targets.
|
||||
pub(crate) fn stop_nodes(b: &Job, targets: &[(String, bool)], graceful: bool) {
|
||||
for (agent, running) in targets {
|
||||
stop_chain(b, agent, graceful, *running);
|
||||
}
|
||||
}
|
||||
|
||||
/// Assemble the start DAG from explicit `(agent, running, stale)` targets.
|
||||
|
|
@ -231,40 +218,17 @@ pub(crate) fn stop_spec(
|
|||
/// running under its lease, so a down+stale agent that grew a rebuild subgraph
|
||||
/// reports `rebuilding` during its swap and `starting` at its reconcile,
|
||||
/// without the DAG having to guess one label covering every target.
|
||||
pub(crate) fn start_spec(
|
||||
targets: &[(String, bool, bool)],
|
||||
source: Source,
|
||||
reason: String,
|
||||
) -> DagSpec<impl FnOnce(&Job) + use<>> {
|
||||
let targets = targets.to_vec();
|
||||
power_dag(
|
||||
source,
|
||||
reason,
|
||||
Box::new(move |b: &Job| {
|
||||
for (agent, running, stale) in targets {
|
||||
start_chain(b, &agent, running, stale);
|
||||
}
|
||||
}),
|
||||
)
|
||||
pub(crate) fn start_nodes(b: &Job, targets: &[(String, bool, bool)]) {
|
||||
for (agent, running, stale) in targets {
|
||||
start_chain(b, agent, *running, *stale);
|
||||
}
|
||||
}
|
||||
|
||||
/// Assemble the restart DAG from explicit `(agent, running)` targets.
|
||||
pub(crate) fn restart_spec(
|
||||
targets: &[(String, bool)],
|
||||
graceful: bool,
|
||||
source: Source,
|
||||
reason: String,
|
||||
) -> DagSpec<impl FnOnce(&Job) + use<>> {
|
||||
let targets = targets.to_vec();
|
||||
power_dag(
|
||||
source,
|
||||
reason,
|
||||
Box::new(move |b: &Job| {
|
||||
for (agent, running) in targets {
|
||||
restart_chain(b, &agent, graceful, running);
|
||||
}
|
||||
}),
|
||||
)
|
||||
/// Declare the restart DAG from explicit `(agent, running)` targets.
|
||||
pub(crate) fn restart_nodes(b: &Job, targets: &[(String, bool)], graceful: bool) {
|
||||
for (agent, running) in targets {
|
||||
restart_chain(b, agent, graceful, *running);
|
||||
}
|
||||
}
|
||||
|
||||
/// Restart a single agent. Thin wrapper over [`restart_many`].
|
||||
|
|
@ -302,7 +266,9 @@ pub async fn restart_many(
|
|||
for agent in agents {
|
||||
targets.push((agent.clone(), lifecycle::is_running(agent).await));
|
||||
}
|
||||
submit_and_emit(coord, restart_spec(&targets, graceful, source, reason))
|
||||
submit_and_emit(coord, source, reason, |b| {
|
||||
restart_nodes(b, &targets, graceful);
|
||||
})
|
||||
}
|
||||
|
||||
/// Start a single agent. Thin wrapper over [`start_many`].
|
||||
|
|
@ -335,7 +301,9 @@ pub async fn start_many(
|
|||
}
|
||||
targets.push((agent.clone(), running, stale));
|
||||
}
|
||||
submit_and_emit(coord, start_spec(&targets, source, reason))
|
||||
submit_and_emit(coord, source, reason, |b| {
|
||||
start_nodes(b, &targets);
|
||||
})
|
||||
}
|
||||
|
||||
/// Hard stop a single agent. Thin wrapper over [`stop_many`].
|
||||
|
|
@ -371,7 +339,9 @@ pub async fn stop_many(
|
|||
for agent in agents {
|
||||
targets.push((agent.clone(), lifecycle::is_running(agent).await));
|
||||
}
|
||||
submit_and_emit(coord, stop_spec(&targets, graceful, source, reason))
|
||||
submit_and_emit(coord, source, reason, |b| {
|
||||
stop_nodes(b, &targets, graceful);
|
||||
})
|
||||
}
|
||||
|
||||
/// Perm change: commit the JSON file(s) then rebuild.
|
||||
|
|
@ -382,10 +352,9 @@ pub fn perm_change(
|
|||
reason: String,
|
||||
payload: super::PermPayload,
|
||||
) -> u64 {
|
||||
submit_and_emit(
|
||||
coord,
|
||||
templates::perm_change(agent, source, reason, payload),
|
||||
)
|
||||
submit_and_emit(coord, source, reason, |b| {
|
||||
templates::perm_change(b, agent, payload);
|
||||
})
|
||||
}
|
||||
|
||||
/// Meta-input lock bump; cascade rebuilds fan out on completion.
|
||||
|
|
@ -395,7 +364,9 @@ pub fn meta_update(
|
|||
source: Source,
|
||||
reason: String,
|
||||
) -> u64 {
|
||||
submit_and_emit(coord, templates::meta_update(inputs, source, reason, None))
|
||||
submit_and_emit(coord, source, reason, |b| {
|
||||
templates::meta_update(b, inputs, None);
|
||||
})
|
||||
}
|
||||
|
||||
/// Topology move(s) as a queue DAG. `moves` is `(child, new_parent)` pairs —
|
||||
|
|
@ -411,5 +382,7 @@ pub fn reparent(
|
|||
source: Source,
|
||||
reason: String,
|
||||
) -> u64 {
|
||||
submit_and_emit(coord, templates::reparent(moves, source, reason))
|
||||
submit_and_emit(coord, source, reason, |b| {
|
||||
templates::reparent(b, moves);
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue