refactor(#2591): slim the job-queue wire types to a raw-graph projection
WIP (hive-sh4re only; hive-c0re construction follows). Reshapes the dashboard/hivectl queue wire per mara's redesign (#2637): - DagView is now a thin projection: { id, source, reason, created_at, nodes }. Dropped the rolled-up kind (Template)/state/started_at/finished_at/inputs/ approval_id — the client derives label + roll-up state + DAG timestamps from the node set. - NodeView drops step + inline build_log_id; started_at/finished_at are chrono DateTime<Utc> (off the hive_jobq Node); non-derivable per-node payload rides the owning node (approval_id on the approval node, inputs on the meta_lock node). - Deleted the Template enum entirely. Done nodes are excluded from the wire (a fully-done DAG disappears; a failed DAG lingers until the history cap). Build logs move to an on-demand GET /api/build-log/<node_id> query (next commits).
This commit is contained in:
parent
a7f0f3d231
commit
54d144b647
1 changed files with 33 additions and 88 deletions
|
|
@ -6,68 +6,9 @@
|
|||
//! live in `hive-c0re::job_queue`; these are the serialized views it
|
||||
//! produces. Semantics: `docs/coordinator.md::Job queue`.
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// What a DAG *means* — the request-level shape. Wire strings match
|
||||
/// the pre-DAG queue's `kind` values so dashboards key off the same
|
||||
/// tags.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum Template {
|
||||
/// Rebuild one agent's container (prebuild → stop → profile-swap →
|
||||
/// reconcile).
|
||||
Rebuild,
|
||||
/// Bump meta flake locks; grows a rebuild subgraph per affected
|
||||
/// agent into the same DAG on completion.
|
||||
MetaUpdate,
|
||||
/// First-deploy spawn (approval-driven).
|
||||
Spawn,
|
||||
/// Reserved for a future destroy integration.
|
||||
Destroy,
|
||||
/// Mechanical stop + converge to `wanted = Up` (a restart).
|
||||
Restart,
|
||||
/// Signal → drain → mechanical stop → converge to `wanted = Up` — a
|
||||
/// graceful restart as one atomic DAG (drains the harness before the
|
||||
/// stop, same as `GracefulStop`, but then reconciles back up instead
|
||||
/// of staying down).
|
||||
GracefulRestart,
|
||||
/// Perm-file commit followed by the rebuild subgraph.
|
||||
PermChange,
|
||||
/// Quiesce the harness, drain, then stop (`wanted = Offline`).
|
||||
GracefulStop,
|
||||
/// Converge to `wanted = Up`.
|
||||
Start,
|
||||
/// Converge to `wanted = Offline`.
|
||||
Stop,
|
||||
/// Bare converge of observed power state to the persisted intent
|
||||
/// (boot reconcile).
|
||||
Reconcile,
|
||||
/// Boot-time config sweep as one DAG: a hyperhive lock bump that grows
|
||||
/// a rebuild subgraph per stale agent, plus a `Reconcile` per drifted
|
||||
/// agent — all in a single DAG (no anchor node, no child DAGs).
|
||||
Boot,
|
||||
}
|
||||
|
||||
impl Template {
|
||||
#[must_use]
|
||||
pub fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
Template::Rebuild => "rebuild",
|
||||
Template::MetaUpdate => "meta_update",
|
||||
Template::Spawn => "spawn",
|
||||
Template::Destroy => "destroy",
|
||||
Template::Restart => "restart",
|
||||
Template::GracefulRestart => "graceful_restart",
|
||||
Template::PermChange => "perm_change",
|
||||
Template::GracefulStop => "graceful_stop",
|
||||
Template::Start => "start",
|
||||
Template::Stop => "stop",
|
||||
Template::Reconcile => "reconcile",
|
||||
Template::Boot => "boot",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Where the submit request originated — drives the "why" chip on the
|
||||
/// dashboard.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
|
|
@ -140,9 +81,12 @@ pub enum PermPayload {
|
|||
/// so the widening from the old dag-local `u32` is transparent.
|
||||
pub type NodeId = u64;
|
||||
|
||||
/// One node of a queued DAG, as serialized. Step labels, build-log
|
||||
/// links, errors, and timestamps are per-node; the DAG-level `state`
|
||||
/// is a roll-up.
|
||||
/// One node of a queued DAG, serialized near-raw from the scheduler
|
||||
/// graph. Lifecycle (`state` / `started_at` / `finished_at` / `error`)
|
||||
/// comes straight off the `hive_jobq::Node`. The client derives DAG-level
|
||||
/// roll-ups (label, state, timestamps) from the node set — nothing is
|
||||
/// rolled up host-side. Build logs are fetched on demand by node id
|
||||
/// (`GET /api/build-log/<id>`), not carried inline.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct NodeView {
|
||||
pub id: NodeId,
|
||||
|
|
@ -156,44 +100,45 @@ pub struct NodeView {
|
|||
/// `"drain"`, `"write_dropin"`, `"write_perm_file"`,
|
||||
/// `"approval_deploy"`.
|
||||
pub kind: String,
|
||||
/// Ids of the nodes this one waits for.
|
||||
/// Ids of the nodes this one waits for. May reference an already-`Done`
|
||||
/// node that's been filtered out of the wire — the client treats a dep
|
||||
/// on an absent node as satisfied.
|
||||
#[serde(default)]
|
||||
pub deps: Vec<NodeId>,
|
||||
pub state: State,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub step: Option<String>,
|
||||
pub started_at: Option<DateTime<Utc>>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub build_log_id: Option<i64>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub started_at: Option<i64>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub finished_at: Option<i64>,
|
||||
pub finished_at: Option<DateTime<Utc>>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub error: Option<String>,
|
||||
/// Approval-queue row id — present only on the `approval_deploy` node.
|
||||
/// The client links a DAG to its pending approval through this (it is
|
||||
/// not derivable from the graph, so it rides the node that owns it).
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub approval_id: Option<i64>,
|
||||
/// Meta-flake inputs being bumped — present only on the `meta_lock`
|
||||
/// node. Display-only payload, not derivable from the graph.
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub inputs: Vec<String>,
|
||||
}
|
||||
|
||||
/// A queued/running/recent DAG. `kind` = template string, roll-up
|
||||
/// `state`; everything per-node appears exactly once, inside `nodes`.
|
||||
/// There is no DAG-level `agent` — a DAG can span agents, so agent lives
|
||||
/// on each [`NodeView`]; consumers group nodes by `NodeView::agent`.
|
||||
/// A queued / running / failed DAG — a thin projection of one container
|
||||
/// node plus its (non-`Done`) subtree from the scheduler graph. Only
|
||||
/// non-derivable facts live here: `id`, `source`, `reason`, `created_at`,
|
||||
/// and the node set. The client derives the card label, roll-up state, and
|
||||
/// DAG timestamps from `nodes` (per-node `kind` + lifecycle) — nothing is
|
||||
/// rolled up host-side. There is no DAG-level `agent`: a DAG can span
|
||||
/// agents, so agent is per-[`NodeView`]; consumers group by `NodeView::agent`.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct DagView {
|
||||
pub id: u64,
|
||||
/// Template wire string — same values the old `kind` field used.
|
||||
pub kind: Template,
|
||||
/// Roll-up: `failed` if any node failed, else `running` /
|
||||
/// `queued` / `cancelled` / `done`.
|
||||
pub state: State,
|
||||
pub source: Source,
|
||||
pub reason: String,
|
||||
pub enqueued_at: i64,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub started_at: Option<i64>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub finished_at: Option<i64>,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub inputs: Vec<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub approval_id: Option<i64>,
|
||||
/// When the DAG was enqueued.
|
||||
pub created_at: DateTime<Utc>,
|
||||
/// Nodes of this DAG with `Done` ones excluded. A DAG whose nodes are
|
||||
/// all `Done` is omitted from the snapshot entirely; a `Failed` DAG
|
||||
/// lingers until aged out by the history cap.
|
||||
pub nodes: Vec<NodeView>,
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue