feat(job-queue): promote the meta-repo deploy window to a queue resource
The two-phase approval deploy keeps a bumped `flake.lock` staged uncommitted for the whole container build, so no other meta mutation may land inside that span — until now enforced by a process-global `meta::exclusive()` mutex held inside each executor fn. A `MutexGuard` cannot outlive the fn that takes it, which is what blocks decomposing the opaque `ApprovalDeploy` node into scheduler-visible sub-nodes: the window has to span them. Replace the mutex with `Resource::MetaWindow`, a global capacity-1 queue resource declared by every meta-mutating node kind (`NodeKind::needs_meta_window`). Resources are held by a subtree root across its whole subtree, so a later increment can hang the deploy's phases under one window-holding parent. Same global serialisation as before, and the scheduler now blocks a node from being claimed rather than parking a worker on a mutex. Split the rebuild's meta preamble out of `Prebuild` into a new `MetaSync` node. `Prebuild` must NOT hold the window: the old mutex was deliberately scoped to drop before the multi-minute toplevel build, which only reads the store, and a cap-1 global held across it would serialise every agent's rebuild behind every other's. `MetaSync` is a sibling root that `Prebuild` deps `AfterOk` on — not its parent, since a parent's resource covers its whole subtree and would reintroduce exactly that problem. Queue tests: shape assertions gain the extra node, which is the point of the change (phases become nodes). The concurrency invariants are intact but observed one step later — the `MetaSync` heads take turns on the window, exactly as the runtime mutex made them, so those tests now complete the heads before asserting that the prebuilds overlap.
This commit is contained in:
parent
2316287327
commit
dfadacd45f
8 changed files with 311 additions and 148 deletions
|
|
@ -95,8 +95,9 @@ fn start_chain(agent: &str, running: bool, stale: bool) -> Vec<NodeSpec> {
|
|||
)];
|
||||
if !running && stale {
|
||||
// Rebuild subtree after the SetWanted head (base = 1, so the rebuild's
|
||||
// `Prebuild` root deps `after_ok(0)` = the head). `Prebuild` +
|
||||
// `Reconcile` are their own group roots (top-level, per `rebuild_nodes`).
|
||||
// `MetaSync` root deps `after_ok(0)` = the head). `MetaSync`,
|
||||
// `Prebuild` + `Reconcile` are their own group roots (top-level, per
|
||||
// `rebuild_nodes`).
|
||||
n.extend(rebuild_nodes(agent, true, 1));
|
||||
} else {
|
||||
n.push(child(
|
||||
|
|
|
|||
Loading…
Reference in a new issue