docs: job-DAG queue model; fold agent_power table into broker.sqlite
coordinator.md rewrites the queue section (node inventory, DAG shapes, resources, desired-state reconciliation, boot reconcile); approvals.md + persistence.md + hivectl --graceful help updated to match. agent_power lives in broker.sqlite like approvals/questions (own connection + busy timeout) instead of a separate db file.
This commit is contained in:
parent
8349e6f621
commit
604e1c2557
8 changed files with 293 additions and 203 deletions
|
|
@ -139,11 +139,11 @@ enum Cmd {
|
|||
#[command(flatten)]
|
||||
scope: ScopeArgs,
|
||||
/// Gracefully quiesce each agent before stopping, instead of a
|
||||
/// hard stop. Each agent is enqueued as a `GracefulStop` on the
|
||||
/// rebuild queue: the harness is signalled, runs one
|
||||
/// stop-checkpoint turn to flush durable `/state`, drains, then
|
||||
/// the container is stopped (bounded by a 3-min timeout that
|
||||
/// falls back to a hard stop). Applies to agents only.
|
||||
/// hard stop. Each agent gets a graceful-stop DAG on the job
|
||||
/// queue: the harness is signalled, runs one stop-checkpoint
|
||||
/// turn to flush durable `/state`, drains, then the container
|
||||
/// is stopped (bounded by a 3-min timeout that falls back to a
|
||||
/// hard stop). All drains overlap. Applies to agents only.
|
||||
#[arg(long)]
|
||||
graceful: bool,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -490,8 +490,7 @@ impl Coordinator {
|
|||
let audit_log =
|
||||
Arc::new(crate::audit_log::AuditLog::open(build_logs_dir).context("open audit_log")?);
|
||||
crate::audit_log::install(audit_log.clone());
|
||||
let power =
|
||||
Arc::new(crate::power::PowerStore::open(build_logs_dir).context("open agent_power")?);
|
||||
let power = Arc::new(crate::power::PowerStore::open(db_path).context("open agent_power")?);
|
||||
let (dashboard_events, _) = broadcast::channel(DASHBOARD_CHANNEL);
|
||||
let (shutdown_tx, _) = watch::channel(false);
|
||||
Ok(Self {
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ async fn run_swap(coord: &Arc<Coordinator>, claim: &Claim, ctx: &Ctx<'_>) -> Res
|
|||
let paths = Coordinator::agent_paths(name, agent_dir);
|
||||
let result =
|
||||
crate::lifecycle::swap_update(name, &hive, &paths, &|step| ctx.step(step), &|log_id| {
|
||||
ctx.build_log(log_id)
|
||||
ctx.build_log(log_id);
|
||||
})
|
||||
.await;
|
||||
match &result {
|
||||
|
|
|
|||
|
|
@ -3,8 +3,11 @@
|
|||
//! `container_view` remains the observed *status*; the job queue's
|
||||
//! `Reconcile` nodes are the mechanism that converges the two.
|
||||
//!
|
||||
//! Stored in `/var/lib/hyperhive/db/agent_power.sqlite` (one tiny row
|
||||
//! per agent). Intent persists across hive-c0re restarts; in-flight
|
||||
//! Stored as the `agent_power` table in the coordinator DB
|
||||
//! (`/var/lib/hyperhive/db/broker.sqlite`, one tiny row per agent) —
|
||||
//! same one-file-many-modules pattern as `approvals` /
|
||||
//! `operator_questions` / `scheduled_prompts`, each with its own
|
||||
//! connection. Intent persists across hive-c0re restarts; in-flight
|
||||
//! queue work deliberately does not. Setting `wanted` is never a
|
||||
//! queued node: operator/intent actions update the row synchronously
|
||||
//! at request time, then submit the DAG whose terminal `Reconcile`
|
||||
|
|
@ -80,12 +83,21 @@ pub struct PowerStore {
|
|||
}
|
||||
|
||||
impl PowerStore {
|
||||
pub fn open(db_dir: &Path) -> Result<Self> {
|
||||
std::fs::create_dir_all(db_dir)
|
||||
.with_context(|| format!("create agent_power db parent {}", db_dir.display()))?;
|
||||
let path = db_dir.join("agent_power.sqlite");
|
||||
let conn = Connection::open(&path)
|
||||
.with_context(|| format!("open agent_power db {}", path.display()))?;
|
||||
/// Open (a connection to) the shared coordinator DB and ensure the
|
||||
/// `agent_power` table exists. `db_path` is the same sqlite file
|
||||
/// the broker / approvals / questions stores open.
|
||||
pub fn open(db_path: &Path) -> Result<Self> {
|
||||
if let Some(parent) = db_path.parent() {
|
||||
std::fs::create_dir_all(parent)
|
||||
.with_context(|| format!("create agent_power db parent {}", parent.display()))?;
|
||||
}
|
||||
let conn = Connection::open(db_path)
|
||||
.with_context(|| format!("open agent_power db {}", db_path.display()))?;
|
||||
// Several modules hold their own connection to this file (the
|
||||
// broker / approvals / questions pattern); wait out a
|
||||
// concurrent writer instead of surfacing SQLITE_BUSY.
|
||||
conn.busy_timeout(std::time::Duration::from_secs(5))
|
||||
.context("set agent_power busy_timeout")?;
|
||||
conn.execute_batch(SCHEMA)
|
||||
.context("apply agent_power schema")?;
|
||||
Ok(Self {
|
||||
|
|
|
|||
Loading…
Reference in a new issue