fix(#3034): run prebuild beside the graceful-stop window, braced by AgentWindow
The graceful path hung `Signal` under `Prebuild`, and a child only starts once its parent's own logic completes — so the drain window waited for the entire nix build before the agent was even asked to checkpoint. Up to the full GRACEFUL_STOP_TIMEOUT hidden behind the build, per agent, on every boot sweep. `Prebuild` needs the build slot and `Signal`/`Drain` need the agent lease, so there was never any contention to justify the nesting. Adds `NodeKind::AgentWindow`, a pure resource holder in the `DeployWindow` pattern. It declares the build slot and the agent lease atomically and holds both for its whole subtree; `Prebuild` and the quiesce chain hang off it as siblings and run concurrently. `StopForUpdate` is AfterOk *both*, so the container still goes down only once the build is ready and the agent has checkpointed — running the drain early is the win, stopping early would just be downtime. Two things this deliberately reverses, both documented in place: * The coordinated children now declare no resources. `templates.rs`'s module doc said each node must declare its own, precisely so one running under a holding ancestor could not get away with declaring nothing. That rule stands; the brace is named as its one exception, because declaring a resource means "I need this exclusively" and the lease is single-unit — two siblings that both declared it could never overlap, which is the whole point of the shape. * `rebuild_chain_declares_the_slot_where_the_nix_work_is` asserted the old principle in its name. Renamed to `..._declares_its_resources_on_the_brace` rather than left saying something the code no longer does. Hoisting the build slot is not new serialisation: a unit is held until the acquirer's subtree settles, and everything downstream already sat inside `Prebuild`, so the slot already spanned the entire rebuild. `graceful_rebuild_chain_drains_before_stopping` now asserts full rows instead of the kind list — the kind list is identical whether the chain runs beside the build or under it, so it could not see this bug. Verified by mutation: re-nesting `Signal` under `Prebuild` fails exactly that one test out of 317.
This commit is contained in:
parent
289db00321
commit
31a1853a45
4 changed files with 295 additions and 140 deletions
|
|
@ -126,13 +126,18 @@ pub(super) async fn run_node(
|
|||
Ok(())
|
||||
}
|
||||
NodeKind::SetWanted { up, .. } => run_set_wanted(coord, agent, *up),
|
||||
// The two nodes that carry no work of their own; completing either
|
||||
// lets it reach `Finishing` so the nodes under it start.
|
||||
// The nodes that carry no work of their own; completing one lets it
|
||||
// reach `Finishing` so the nodes under it start.
|
||||
// - `Dag`: pure grouping container. The DAG's terminal side effect, if
|
||||
// any, is its own tail node in the graph.
|
||||
// - `DeployWindow`: pure resource holder — the meta window, agent lease
|
||||
// and build slot it declares stay held until its subtree settles.
|
||||
NodeKind::Dag { .. } | NodeKind::DeployWindow { .. } => Ok(()),
|
||||
// - `AgentWindow`: pure resource holder for one agent's rebuild — holds
|
||||
// the lease so the build and the graceful-stop window can run as
|
||||
// siblings rather than one nested under the other.
|
||||
NodeKind::Dag { .. } | NodeKind::DeployWindow { .. } | NodeKind::AgentWindow { .. } => {
|
||||
Ok(())
|
||||
}
|
||||
};
|
||||
(builder, result)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue