defer start-after-rebuild to the fast lane so the build lane frees up (closes #2094)

This commit is contained in:
damocles 2026-07-01 23:37:13 +02:00
commit b191858366
6 changed files with 162 additions and 61 deletions

View file

@ -890,21 +890,12 @@ async fn dispatch(
dispatch_rebuild_approval(coord, entry, approval_id).await
}
(QueueKind::Rebuild, None) => {
let current_rev =
crate::auto_update::current_flake_rev(&coord.hyperhive_flake).unwrap_or_default();
// A meta-update cascade has just set the meta lock; re-locking
// in the per-agent rebuild would revert it (the agent's own
// flake.lock wins). Every other source wants the relock so it
// advances to applied/<n>/main.
let relock = entry.source != QueueSource::MetaUpdate;
crate::auto_update::rebuild_agent(
coord,
&entry.agent,
&current_rev,
Some(entry.id),
relock,
)
.await
rebuild_for_entry(coord, entry, relock).await
}
(QueueKind::MetaUpdate, Some(approval_id)) => {
crate::actions::run_approval_update_meta_inputs(coord, Some(entry.id), approval_id)
@ -1002,9 +993,7 @@ async fn dispatch(
}
// Now rebuild so the updated HIVE_TOOL_GROUPS / HIVE_CAPABILITIES
// env var takes effect in the container.
let current_rev =
crate::auto_update::current_flake_rev(&coord.hyperhive_flake).unwrap_or_default();
crate::auto_update::rebuild_agent(coord, name, &current_rev, Some(entry.id), true).await
rebuild_for_entry(coord, entry, true).await
}
(QueueKind::GracefulStop, _) => {
run_graceful_stop(coord, entry);
@ -1015,9 +1004,36 @@ async fn dispatch(
}
}
/// Queue-side container rebuild for `entry.agent`: resolves the current
/// flake rev and hands off to `rebuild_agent` with the entry's id +
/// source. Passing the source defers the start-after-rebuild to a
/// fast-lane `Start` follow-up (grouped under this entry via
/// `parent_id`), so the build lane is freed for the next entry instead
/// of waiting out the container boot.
async fn rebuild_for_entry(
coord: &std::sync::Arc<crate::coordinator::Coordinator>,
entry: &QueueEntry,
relock: bool,
) -> anyhow::Result<()> {
let current_rev =
crate::auto_update::current_flake_rev(&coord.hyperhive_flake).unwrap_or_default();
crate::auto_update::rebuild_agent(
coord,
&entry.agent,
&current_rev,
Some(entry.id),
relock,
Some(entry.source),
)
.await
}
/// Start a stopped container off the queue (`QueueKind::Start`), with a
/// `Starting` transient so the dashboard shows a visible queued→running
/// progression rather than the sub-second flash of a direct start.
/// Uses the cold-start fallback (stop + kill + start retry) so the
/// deferred start-after-rebuild keeps the same activation-error recovery
/// it had when it ran inline on the build lane.
async fn run_start(
coord: &std::sync::Arc<crate::coordinator::Coordinator>,
entry: &QueueEntry,
@ -1025,7 +1041,7 @@ async fn run_start(
let name = &entry.agent;
let _guard = coord.transient_guard(name, crate::coordinator::TransientKind::Starting);
coord.set_queue_step(Some(entry.id), "nixos-container start");
crate::lifecycle::start(name).await?;
crate::lifecycle::start_with_fallback(name).await?;
coord.kick_agent(name, "container started");
coord.rescan_containers_and_emit().await;
Ok(())