job_queue: grow the rebuild subgraph from DeployApply (#2664)
The config-PR deploy's apply node still did the whole container rebuild inline, through the last surviving `lifecycle::rebuild_no_meta` call. It now merges, opens the two-phase meta deploy, and returns the ordinary rebuild chain as a subgraph the scheduler grafts into the live DAG under it. A new `FinalizeDeploy` node, gated on that graft, plants the deploy tag and commits the staged lock. Net effect: "did the agent come back up?" is answered by `Reconcile` succeeding, the same way it is for every other rebuild, instead of by a fused inline start — and each deploy phase is its own queue node, so the dashboard shows which one is running. The grafted nodes root on the apply node, so they land inside `DeployWindow`'s subtree and re-enter the meta window and build slot it already holds rather than deadlocking against them. The new happy-path test runs on a one-slot queue specifically to pin that down. `FinalizeDeploy`'s two git writes are fatal, deliberately: they are what tells `DeployTail` a deploy confirmed good, so a node that merely warned on them could report success while leaving the tail looking at the git state of a failure — and the tail would then roll a good deploy back. The trailing `meta::finalize_deploy` stays warn-only, since by then the container already runs the new config. The `failed/<id>` annotated tag moves into the tail, which is now the only place holding a failed deploy. It reads the reason off the DAG via a new `JobQueue::first_error`, and is gated on `main` having actually moved — the rollback ref is parked *before* the merge, so its existence alone does not mean a merge happened, and a pre-merge rejection must not tag the previous, innocent head. Removing the last inline rebuild orphaned a chain of now-dead code: `rebuild_no_meta`, `container_exists`, `Coordinator::set_queue_build_log` and `JobQueue::set_build_log_id_running`, all deleted here.
This commit is contained in:
parent
7b2645078a
commit
3429a8c5a6
10 changed files with 388 additions and 257 deletions
|
|
@ -31,7 +31,7 @@ pub struct NodeOutput {
|
|||
/// runtime — the single in-DAG-growth channel. Each inner
|
||||
/// `Vec<NodeSpec>` is one independent subgraph whose `deps` are local
|
||||
/// (0-based within that subgraph); the scheduler appends each via
|
||||
/// [`JobQueue::append_subgraph`], which rebases the deps onto the DAG's
|
||||
/// [`super::JobQueue::append_subgraph`], which rebases the deps onto the DAG's
|
||||
/// node-id space and roots the subgraph on the emitting node. Used both
|
||||
/// for the multi-node case (`MetaLock` growing one rebuild subgraph per
|
||||
/// agent — the startup sweep's stale agents, the meta-update cascade's
|
||||
|
|
@ -102,6 +102,7 @@ pub(super) async fn run_node(coord: &Arc<Coordinator>, claim: &Claim) -> Result<
|
|||
NodeKind::DeployWindow { .. } => run_deploy_window(claim),
|
||||
NodeKind::MergeVerify { .. } => run_merge_verify(coord, claim).await,
|
||||
NodeKind::DeployApply { .. } => run_deploy_apply(coord, claim).await,
|
||||
NodeKind::FinalizeDeploy { .. } => run_finalize_deploy(coord, claim).await,
|
||||
NodeKind::DeployTail { .. } => run_deploy_tail(coord, claim).await,
|
||||
NodeKind::SetWanted { up, .. } => run_set_wanted(coord, claim, *up),
|
||||
// Pure grouping container — no work; completing it lets it reach
|
||||
|
|
@ -615,10 +616,27 @@ async fn run_merge_verify(coord: &Arc<Coordinator>, claim: &Claim) -> Result<Nod
|
|||
.map(|()| NodeOutput::default())
|
||||
}
|
||||
|
||||
/// Deploy phase 2 — the irreversible half: ff-merge, two-phase meta deploy,
|
||||
/// container rebuild, finalize.
|
||||
/// Deploy phase 2 — the irreversible half: ff-merge, then phase 1 of the
|
||||
/// two-phase meta deploy.
|
||||
///
|
||||
/// On success it grows the ordinary rebuild subgraph (plus its closing
|
||||
/// `FinalizeDeploy`) into this DAG rooted on *this* node — which is what puts
|
||||
/// the appended nodes inside the `DeployWindow`'s subtree, so the `MetaWindow`
|
||||
/// their `MetaSync` declares is re-entered rather than deadlocked against the
|
||||
/// ancestor already holding it. On failure nothing is appended and the tail
|
||||
/// compensates, exactly as before.
|
||||
async fn run_deploy_apply(coord: &Arc<Coordinator>, claim: &Claim) -> Result<NodeOutput> {
|
||||
crate::actions::run_deploy_apply(coord, Some(claim.dag_id), deploy_approval_id(claim)?)
|
||||
crate::actions::run_deploy_apply(coord, Some(claim.dag_id), deploy_approval_id(claim)?).await?;
|
||||
Ok(NodeOutput {
|
||||
append_subgraph: vec![super::templates::deploy_rebuild_nodes(claim.kind.agent())],
|
||||
})
|
||||
}
|
||||
|
||||
/// Deploy phase 3 — close the staged-lock window once the appended rebuild has
|
||||
/// come up clean: drop the rollback ref, plant the `deployed/<id>` tag, commit
|
||||
/// the staged lock.
|
||||
async fn run_finalize_deploy(coord: &Arc<Coordinator>, claim: &Claim) -> Result<NodeOutput> {
|
||||
crate::actions::run_finalize_deploy(coord, Some(claim.dag_id), deploy_approval_id(claim)?)
|
||||
.await
|
||||
.map(|()| NodeOutput::default())
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue