c0re's queue tests no longer drive the scheduler
The last two claim-driven tests were both arranging node states to observe something that never needed a run: `settled_dag_leaves_the_snapshot_despite_its_skipped_branch` completed all seven nodes of a rebuild to assert the DAG left the snapshot. That is one predicate over a list of states. `shown_on_wire` is it, split out of `dag_view`, and the cases can now be named rather than arranged — including the empty set, the one input where "any" and "all" disagree. It takes states rather than projected nodes so the caller skips projecting what it is about to discard; a `NodeView` costs a `build_logs` lookup. `failed_node_cancels_downstream_but_afterany_reconcile_runs` asserted three unrelated things from one arranged failure: the cascade (hive_jobq's, and already tested there), the wire filter (now `shown_on_wire`), and the roll-up. `DagView::rollup_state` lives in hive-host-sock, which had no tests at all — it does now, next to the invariant, covering the ordering its own doc comment says has silently disagreed with the frontend before. With nothing left claiming, `Claimed` / `ClaimReady` / `CompleteNode` / `claim_one` / `settle_rebuild_tail` are deleted. Claim/complete sites in `job_queue/tests.rs`: 109 -> 0. jobq narrows to match: `settle` is gone (it was a `claim_one` loop returning a Vec, and its only callers were tests — it lives in the test module now), `claim_one` is private, and `complete_growing` is `pub(crate)`. `claim_next` is the whole run-loop surface. `complete` stays `pub` for one caller, noted at the definition: `submit` completes a group root with no logic of its own so it parks in `Finishing` and its children unblock. That is a statement about the node, not an event to report, and it wants to be expressible at insert time.
This commit is contained in:
parent
ab5744a2bd
commit
e646656c92
4 changed files with 334 additions and 266 deletions
|
|
@ -404,32 +404,27 @@ fn dag_meta(sched: &Sched, container: NodeId) -> Option<DagMeta> {
|
|||
/// aged out).
|
||||
fn dag_view(sched: &Sched, container: NodeId) -> Option<DagView> {
|
||||
let meta = dag_meta(sched, container)?;
|
||||
let mut nodes = Vec::new();
|
||||
// Whether anything in this DAG still has an outcome worth showing.
|
||||
// Kept separate from `nodes` being non-empty: skipped nodes ride the
|
||||
// wire so the dashboard can mark the branches that weren't taken, but
|
||||
// they must not by themselves hold a finished DAG in the snapshot.
|
||||
let mut any_unsettled = false;
|
||||
let all: Vec<_> = sched.graph().descendants(container).collect();
|
||||
// DAG-level timestamps are taken over *all* subtree nodes (including the
|
||||
// `Done` ones excluded from the wire) — the client can't derive them
|
||||
// from a `Done`-filtered node set, so the host computes them here.
|
||||
let mut started: Vec<DateTime<Utc>> = Vec::new();
|
||||
let mut finished: Vec<DateTime<Utc>> = Vec::new();
|
||||
for node in sched.graph().descendants(container) {
|
||||
let id = node.id;
|
||||
for node in &all {
|
||||
if let Some(s) = node.started_at {
|
||||
started.push(s);
|
||||
}
|
||||
if let Some(f) = node.finished_at {
|
||||
finished.push(f);
|
||||
}
|
||||
// `Done` nodes drop off the wire — a finished step isn't
|
||||
// interesting. `Skipped` ones stay: which branch a run *didn't*
|
||||
// take is the readable half of an outcome-branched DAG.
|
||||
if matches!(node.state, State::Done) {
|
||||
continue;
|
||||
}
|
||||
any_unsettled |= !matches!(node.state, State::Skipped);
|
||||
}
|
||||
// Decide which nodes ride the wire *before* projecting any of them: a
|
||||
// `NodeView` costs a `build_logs` lookup, so building one for a node
|
||||
// that's about to be dropped would be a query per finished step.
|
||||
let shown = shown_on_wire(&all.iter().map(|n| n.state).collect::<Vec<_>>())?;
|
||||
let mut nodes = Vec::new();
|
||||
for node in shown.into_iter().map(|i| all[i]) {
|
||||
let id = node.id;
|
||||
let deps: Vec<u64> = node
|
||||
.deps
|
||||
.iter()
|
||||
|
|
@ -480,9 +475,6 @@ fn dag_view(sched: &Sched, container: NodeId) -> Option<DagView> {
|
|||
parent,
|
||||
});
|
||||
}
|
||||
if !any_unsettled {
|
||||
return None;
|
||||
}
|
||||
let is_terminal = sched.graph().is_settled(container) == Some(true);
|
||||
Some(DagView {
|
||||
id: container.get(),
|
||||
|
|
@ -495,6 +487,39 @@ fn dag_view(sched: &Sched, container: NodeId) -> Option<DagView> {
|
|||
})
|
||||
}
|
||||
|
||||
/// Which of a DAG's work nodes ride the wire, by index into `states` — or
|
||||
/// `None` when the DAG has nothing left worth showing and drops out of the
|
||||
/// snapshot entirely.
|
||||
///
|
||||
/// Two separate decisions, and conflating them pins every completed deploy in
|
||||
/// the queue view forever:
|
||||
/// - **`Done` drops off the wire.** A finished step isn't interesting.
|
||||
/// `Skipped` stays: which branch a run *didn't* take is the readable half of
|
||||
/// an outcome-branched DAG.
|
||||
/// - **`Skipped` alone doesn't hold a DAG in the snapshot.** So "the node list
|
||||
/// is non-empty" and "there's still something here worth showing" are
|
||||
/// different questions, and only the second one may drop the DAG.
|
||||
///
|
||||
/// Takes states rather than projected nodes so the caller can skip the work of
|
||||
/// projecting what it's about to discard, and so this is testable without a
|
||||
/// graph — the states it keys on are ones only a run can produce.
|
||||
fn shown_on_wire(states: &[State]) -> Option<Vec<usize>> {
|
||||
let worth_showing = states
|
||||
.iter()
|
||||
.any(|s| !matches!(s, State::Done | State::Skipped));
|
||||
if !worth_showing {
|
||||
return None;
|
||||
}
|
||||
Some(
|
||||
states
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(_, s)| !matches!(s, State::Done))
|
||||
.map(|(i, _)| i)
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
|
||||
/// When a DAG's work node finishes on `finished_at` — the max over its
|
||||
/// subtree (read off the graph `Node`, as unix seconds), for the history
|
||||
/// cap ordering.
|
||||
|
|
|
|||
Loading…
Reference in a new issue