feat(queue): link rebuild queue entries to build log rows for live streaming

This commit is contained in:
damocles 2026-06-04 17:33:59 +02:00 committed by mara
commit 7118c5efdd
6 changed files with 101 additions and 9 deletions

View file

@ -214,6 +214,15 @@ pub struct QueueEntry {
/// most entries; serialised only when non-empty.
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub depends_on: Vec<u64>,
/// Row id of the associated `build_logs` entry (opened by the
/// lifecycle worker when `nixos-container update` starts). Set
/// shortly after `state` transitions to `Running`; `None` while
/// `Queued` or for entries that don't open a build log (`Restart`,
/// `PermChange` file-write phase, etc.). Links the queue card to
/// the live-streaming `/api/build-logs/id/{id}/stream` endpoint so
/// the operator can follow the nix build output in real time.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub build_log_id: Option<i64>,
}
/// How many terminal-state entries (`Done` / `Failed` / `Cancelled`)
@ -429,6 +438,7 @@ impl RebuildQueue {
step: None,
perm_payload,
depends_on,
build_log_id: None,
};
inner.entries.push_back(entry);
// Wake the worker. `notify_one` is a no-op when there's no
@ -521,6 +531,24 @@ impl RebuildQueue {
true
}
/// Link a `build_logs` row to a `Running` entry. Called by the
/// lifecycle worker when `nixos-container update` opens a build log
/// row so the dashboard can surface a "view logs" link while the
/// build is in flight. Returns `true` when the row was found and
/// the id was stored; `false` when the entry is no longer in the
/// queue or is not `Running`.
pub fn set_build_log_id(&self, id: u64, log_id: i64) -> bool {
let mut inner = self.inner.lock().expect("rebuild_queue mutex poisoned");
let Some(entry) = inner.entries.iter_mut().find(|e| e.id == id) else {
return false;
};
if entry.state != QueueState::Running {
return false;
}
entry.build_log_id = Some(log_id);
true
}
/// Snapshot the queue for `/api/state` and `RebuildQueueChanged`.
/// Cheap clone — entries are small (~hundreds of bytes each).
pub fn snapshot(&self) -> Vec<QueueEntry> {