feat(hive-c0re): replace rebuild queue with generic job-DAG queue
jobs are now DAGs of primitive nodes (prebuild, stop-for-update, swap, reconcile, signal, drain, ...) driven by one scheduler with N build slots + per-agent lifecycle leases. per-agent power intent (wanted up/offline) is durable in agent_power.sqlite; Reconcile nodes converge observed state to it. kills the graceful-stop watcher thread, the deferred-start follow-up, and the cascade pre-enqueue (fan-out on MetaLock completion instead). tracker: #2166
This commit is contained in:
parent
79a3993def
commit
7946e03fde
25 changed files with 3673 additions and 2731 deletions
|
|
@ -13,8 +13,8 @@ use hive_sh4re::{HostRequest, HostResponse};
|
|||
use hive_c0re::coordinator::{Coordinator, HiveEnv, ServeConfig};
|
||||
use hive_c0re::{
|
||||
agent_sockets, auto_update, broker, client, crash_watch, dashboard, dashboard_events, forge,
|
||||
knowledge, matrix, migrate, rebuild_queue, reminder_scheduler, scheduled_prompts_worker,
|
||||
server, socket_server,
|
||||
job_queue, knowledge, matrix, migrate, reminder_scheduler, scheduled_prompts_worker, server,
|
||||
socket_server,
|
||||
};
|
||||
|
||||
#[derive(Parser)]
|
||||
|
|
@ -85,6 +85,11 @@ enum Cmd {
|
|||
/// option.
|
||||
#[arg(long)]
|
||||
model_prices: Option<String>,
|
||||
/// Override: number of concurrent nix-heavy job-queue nodes
|
||||
/// (prebuild / profile-swap / create / meta lock). Set via the
|
||||
/// `services.hyperhive.c0re.buildSlots` NixOS option.
|
||||
#[arg(long)]
|
||||
build_slots: Option<usize>,
|
||||
},
|
||||
/// Spawn a new agent container directly (`hive-agent-<name>`). Bypasses
|
||||
/// the approval queue — use only as an operator on the host. For
|
||||
|
|
@ -156,6 +161,7 @@ async fn main() -> Result<()> {
|
|||
agent_cpu_quota,
|
||||
agent_memory_max,
|
||||
model_prices,
|
||||
build_slots,
|
||||
} => {
|
||||
// Base config from the --config file (or the built-in
|
||||
// defaults), then apply any per-flag overrides — config
|
||||
|
|
@ -195,7 +201,10 @@ async fn main() -> Result<()> {
|
|||
sc.model_prices =
|
||||
serde_json::from_str(&v).context("--model-prices: invalid JSON")?;
|
||||
}
|
||||
cmd_serve(sc.env, sc.model_prices, db, &cli.socket).await
|
||||
if let Some(v) = build_slots {
|
||||
sc.build_slots = v;
|
||||
}
|
||||
cmd_serve(sc.env, sc.model_prices, sc.build_slots, db, &cli.socket).await
|
||||
}
|
||||
Cmd::Spawn { name } => {
|
||||
render(client::request(&cli.socket, HostRequest::Spawn { name }).await?)
|
||||
|
|
@ -244,6 +253,7 @@ async fn main() -> Result<()> {
|
|||
async fn cmd_serve(
|
||||
env: HiveEnv,
|
||||
model_prices: hive_c0re::hive_stats::PriceTable,
|
||||
build_slots: usize,
|
||||
db: std::path::PathBuf,
|
||||
socket: &std::path::Path,
|
||||
) -> Result<()> {
|
||||
|
|
@ -255,7 +265,7 @@ async fn cmd_serve(
|
|||
// `dashboard_port` is consumed into the Coordinator below; capture the
|
||||
// Copy value first for the dashboard + knowledge-webhook tasks.
|
||||
let dashboard_port = env.dashboard_port;
|
||||
let coord = Arc::new(Coordinator::open(&db, env, model_prices)?);
|
||||
let coord = Arc::new(Coordinator::open(&db, env, model_prices, build_slots)?);
|
||||
socket_server::start_manager(coord.clone())?;
|
||||
// Idempotent pre-flight: rewrite pre-meta-layout applied
|
||||
// repos, ensure proposed repos carry the `applied`
|
||||
|
|
@ -413,25 +423,17 @@ async fn cmd_serve(
|
|||
// and fans the body out to each active target's inbox. See
|
||||
// scheduled_prompts_worker.rs.
|
||||
scheduled_prompts_worker::spawn(coord.clone());
|
||||
// Rebuild-queue worker: drains the global rebuild/meta-update/
|
||||
// spawn queue FIFO so hive-c0re never runs two heavyweight
|
||||
// container ops concurrently. Existing rebuild call sites
|
||||
// (auto_update, dashboard, manager, approval handler) enqueue
|
||||
// here instead of awaiting `rebuild_agent` inline. See
|
||||
// `rebuild_queue.rs`.
|
||||
// Job-queue scheduler: drives the global DAG queue (rebuild /
|
||||
// meta-update / spawn / power ops). Concurrency comes from the
|
||||
// build-slot count + per-agent leases inside the queue, not from
|
||||
// multiple workers — cheap nodes (graceful signals, drains,
|
||||
// reconciles) overlap nix-heavy ones structurally. Call sites
|
||||
// (auto_update, dashboard, manager, approval handler) submit DAGs
|
||||
// instead of awaiting lifecycle work inline. See `job_queue/`.
|
||||
{
|
||||
let q_coord = coord.clone();
|
||||
tokio::spawn(async move {
|
||||
rebuild_queue::run_worker(q_coord).await;
|
||||
});
|
||||
// Fast lane: a second serial worker for hard Start/Stop, running
|
||||
// concurrently with the build worker above so a stop/start never
|
||||
// waits behind a slow build for another container. Per-agent
|
||||
// ordering vs that agent's own build is enforced in the queue's
|
||||
// claim logic (a fast op defers behind its agent's running build).
|
||||
let fast_coord = coord.clone();
|
||||
tokio::spawn(async move {
|
||||
rebuild_queue::run_fast_worker(fast_coord).await;
|
||||
job_queue::scheduler::run_worker(q_coord).await;
|
||||
});
|
||||
}
|
||||
// Forward every broker event onto the unified dashboard
|
||||
|
|
|
|||
Loading…
Reference in a new issue