jobq: split RebuildOpts into two rebuild entry points
RebuildOpts held one real parameter (relock) and one single-call-site flag (graceful). The struct justified itself as swap-protection for two positional bools; with graceful out of the signature there is nothing left to swap. graceful stays an internal switch rather than moving to the caller: it re-parents the stop root (StopForUpdate goes from part_of(prebuild) to part_of(signal)) rather than prepending nodes, so a caller could only declare it by being handed the subtree's internals — and that nesting keeps the agent lease continuous across the whole stop. run_meta_lock no longer returns options: both fields were a pure function of the sweep flag its caller had just passed in. 315 tests pass unchanged.
This commit is contained in:
parent
8db1cbd204
commit
05f84191fb
4 changed files with 80 additions and 110 deletions
|
|
@ -72,7 +72,18 @@ pub(super) async fn run_node(
|
|||
inputs,
|
||||
} => run_meta_lock(coord, *sweep, fanout.clone(), inputs)
|
||||
.await
|
||||
.map(|(agents, opts)| super::templates::grown_rebuilds(&job, &agents, opts)),
|
||||
.map(|agents| {
|
||||
// `sweep` is the whole difference: it relocks per-agent like a
|
||||
// manual rebuild, and it drains agents that were mid-turn when
|
||||
// the host came up. A cascade does neither. Decided here rather
|
||||
// than returned, since `run_meta_lock` would only be deriving
|
||||
// it from the `sweep` this call site already holds.
|
||||
if *sweep {
|
||||
super::templates::grown_graceful_rebuilds(&job, &agents, true);
|
||||
} else {
|
||||
super::templates::grown_rebuilds(&job, &agents, false);
|
||||
}
|
||||
}),
|
||||
NodeKind::Reconcile { .. } => run_reconcile(coord, agent).await.map(|sub| {
|
||||
if let Some(kind) = sub {
|
||||
super::templates::fanned_out_mechanical(&job, kind);
|
||||
|
|
@ -313,35 +324,29 @@ async fn run_create(name: &str) -> Result<()> {
|
|||
/// the current lock, exactly like today's sweep); the meta-update
|
||||
/// flavour propagates errors, and a failed bump fans out nothing.
|
||||
/// Returns the agents whose rebuild subgraphs the caller should grow into this
|
||||
/// node, and the options to build them with — rather than declaring them here.
|
||||
/// The declaration has to happen outside any `.await` (see [`run_node`]).
|
||||
/// node, rather than declaring them here — the declaration has to happen outside
|
||||
/// any `.await` (see [`run_node`]).
|
||||
///
|
||||
/// Only the agent list: *which* rebuild flavour to grow is a pure function of
|
||||
/// `sweep`, which the caller passed in, so returning it too would be a round
|
||||
/// trip rather than a decision.
|
||||
async fn run_meta_lock(
|
||||
coord: &Arc<Coordinator>,
|
||||
sweep: bool,
|
||||
fanout: Option<Vec<String>>,
|
||||
inputs: &[String],
|
||||
) -> Result<(Vec<String>, super::templates::RebuildOpts)> {
|
||||
) -> Result<Vec<String>> {
|
||||
if sweep {
|
||||
if let Err(e) = crate::meta::lock_update_hyperhive().await {
|
||||
tracing::warn!(error = ?e, "startup sweep: meta lock_update_hyperhive failed");
|
||||
}
|
||||
// Grow one rebuild subgraph per stale agent into *this* boot DAG
|
||||
// (rooted on this `MetaLock`, so they build against the post-bump
|
||||
// lock), rather than fanning out child DAGs. `relock = true` — a
|
||||
// boot sweep relocks per-agent like a manual rebuild.
|
||||
//
|
||||
// `graceful = true` here and nowhere else: a boot sweep stops agents
|
||||
// that were already mid-turn when the host came up, so they get their
|
||||
// drain window rather than being cut off. The per-agent drains overlap,
|
||||
// so the sweep's cost ceiling is one `GRACEFUL_STOP_TIMEOUT` in total,
|
||||
// not one per agent.
|
||||
return Ok((
|
||||
fanout.unwrap_or_default(),
|
||||
super::templates::RebuildOpts {
|
||||
relock: true,
|
||||
graceful: true,
|
||||
},
|
||||
));
|
||||
// lock), rather than fanning out child DAGs. The caller grows them
|
||||
// with the graceful flavour: the per-agent drains overlap, so the
|
||||
// sweep's cost ceiling is one `GRACEFUL_STOP_TIMEOUT` in total, not
|
||||
// one per agent.
|
||||
return Ok(fanout.unwrap_or_default());
|
||||
}
|
||||
let _progress = coord.meta_update_guard();
|
||||
crate::meta::lock_update(inputs).await?;
|
||||
|
|
@ -357,13 +362,7 @@ async fn run_meta_lock(
|
|||
// cascade children must NOT re-lock, which would revert the bump this
|
||||
// node just committed (the property the old `fanout_specs` meta-update
|
||||
// branch encoded).
|
||||
Ok((
|
||||
cascade,
|
||||
super::templates::RebuildOpts {
|
||||
relock: false,
|
||||
graceful: false,
|
||||
},
|
||||
))
|
||||
Ok(cascade)
|
||||
}
|
||||
|
||||
/// Idempotent power-converge *planner*: compare `wanted` (durable
|
||||
|
|
|
|||
Loading…
Reference in a new issue