job_queue: declare a node's resources where the node is constructed
Resources were derived from the node's kind: `templates::node` called `NodeKind::resource_deps()`, which fanned out to `needs_build_slot` / `needs_lease` / `needs_meta_window`. That made the requirement a property of the *kind*, so a kind that happened to run under an ancestor already holding the resource could get away with declaring nothing. Three did. `Start`, `Stop` and `PostSwap` appear in none of the three predicates, and that was only safe because one construction site fans them out from inside a lease-holding `Reconcile` — a fact about today's DAG shape, not about the nodes. Each of the 41 construction sites now says what it holds. `Start` / `Stop` / `PostSwap` declare the agent lease; per the contract that is a re-entrant borrow, which a new test pins rather than argues. `running_transients` reads the node's declared deps instead of re-deriving from the kind. That closes the blank-pill gap: the pill went blank during container start, stop and the post-swap tail because the declaration was missing, not because the filter was wrong. The deleted predicates carried the only written record of three design decisions; each moved to the `Resource` variant it constrains rather than dying with its function.
This commit is contained in:
parent
1aa88463a0
commit
10dbdb444d
9 changed files with 256 additions and 177 deletions
|
|
@ -25,6 +25,7 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use super::model::{DagSpec, NodeKind};
|
||||
use super::resource::Resource;
|
||||
use super::templates::{RebuildOpts, node, rebuild_nodes};
|
||||
use super::{Job, Source, templates};
|
||||
use crate::coordinator::Coordinator;
|
||||
|
|
@ -70,19 +71,26 @@ fn stop_chain(b: &Job, agent: &str, graceful: bool, running: bool) {
|
|||
agent: a(),
|
||||
up: false,
|
||||
},
|
||||
);
|
||||
)
|
||||
.needs(Resource::Agent(a()));
|
||||
// Declaration order is dependency order: the quiesce steps come first so
|
||||
// the `Reconcile` that waits on them can name them.
|
||||
if graceful && running {
|
||||
let signal = node(b, NodeKind::Signal { agent: a() }).part_of(wanted);
|
||||
let signal = node(b, NodeKind::Signal { agent: a() })
|
||||
.needs(Resource::Agent(a()))
|
||||
.part_of(wanted);
|
||||
let drain = node(b, NodeKind::Drain { agent: a() })
|
||||
.needs(Resource::Agent(a()))
|
||||
.part_of(wanted)
|
||||
.after_ok(signal);
|
||||
let _ = node(b, NodeKind::Reconcile { agent: a() })
|
||||
.needs(Resource::Agent(a()))
|
||||
.part_of(wanted)
|
||||
.after_ok(drain);
|
||||
} else {
|
||||
let _ = node(b, NodeKind::Reconcile { agent: a() }).part_of(wanted);
|
||||
let _ = node(b, NodeKind::Reconcile { agent: a() })
|
||||
.needs(Resource::Agent(a()))
|
||||
.part_of(wanted);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -97,7 +105,8 @@ fn start_chain(b: &Job, agent: &str, running: bool, stale: bool) {
|
|||
agent: agent.to_owned(),
|
||||
up: true,
|
||||
},
|
||||
);
|
||||
)
|
||||
.needs(Resource::Agent(agent.to_owned()));
|
||||
if !running && stale {
|
||||
// Rebuild subtree chained behind the `SetWanted` head. `MetaSync`,
|
||||
// `Prebuild` + `Reconcile` are their own group roots (top-level, per
|
||||
|
|
@ -118,6 +127,7 @@ fn start_chain(b: &Job, agent: &str, running: bool, stale: bool) {
|
|||
agent: agent.to_owned(),
|
||||
},
|
||||
)
|
||||
.needs(Resource::Agent(agent.to_owned()))
|
||||
.part_of(wanted);
|
||||
}
|
||||
}
|
||||
|
|
@ -135,7 +145,7 @@ fn restart_chain(b: &Job, agent: &str, graceful: bool, running: bool) {
|
|||
let a = || agent.to_owned();
|
||||
if !running {
|
||||
// Nothing to bounce — a lone Reconcile converges to intent.
|
||||
let _ = node(b, NodeKind::Reconcile { agent: a() });
|
||||
let _ = node(b, NodeKind::Reconcile { agent: a() }).needs(Resource::Agent(a()));
|
||||
return;
|
||||
}
|
||||
// Running: mechanical stop then Reconcile. The first stop node is the group
|
||||
|
|
@ -147,17 +157,23 @@ fn restart_chain(b: &Job, agent: &str, graceful: bool, running: bool) {
|
|||
// that step *is* the root, and the parent gate already orders it — a child
|
||||
// must NOT dep on its own parent (dep-scope), so it takes no sibling edge.
|
||||
if graceful {
|
||||
let signal = node(b, NodeKind::Signal { agent: a() });
|
||||
let drain = node(b, NodeKind::Drain { agent: a() }).part_of(signal);
|
||||
let signal = node(b, NodeKind::Signal { agent: a() }).needs(Resource::Agent(a()));
|
||||
let drain = node(b, NodeKind::Drain { agent: a() })
|
||||
.needs(Resource::Agent(a()))
|
||||
.part_of(signal);
|
||||
let stop = node(b, NodeKind::StopForUpdate { agent: a() })
|
||||
.needs(Resource::Agent(a()))
|
||||
.part_of(signal)
|
||||
.after_ok(drain);
|
||||
let _ = node(b, NodeKind::Reconcile { agent: a() })
|
||||
.needs(Resource::Agent(a()))
|
||||
.part_of(signal)
|
||||
.after_ok(stop);
|
||||
} else {
|
||||
let stop = node(b, NodeKind::StopForUpdate { agent: a() });
|
||||
let _ = node(b, NodeKind::Reconcile { agent: a() }).part_of(stop);
|
||||
let stop = node(b, NodeKind::StopForUpdate { agent: a() }).needs(Resource::Agent(a()));
|
||||
let _ = node(b, NodeKind::Reconcile { agent: a() })
|
||||
.needs(Resource::Agent(a()))
|
||||
.part_of(stop);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue