fix(#1932): hivectl start restores only the previously-running agents

This commit is contained in:
damocles 2026-06-23 14:59:40 +02:00 committed by mara
commit 6516d4282e
2 changed files with 57 additions and 2 deletions

View file

@ -131,6 +131,15 @@ pub struct Coordinator {
/// agent is in this set — the inbound fence. Cleared when the agent
/// reports `GracefulStopComplete` or the container is stopped.
graceful_stop_pending: Mutex<HashSet<String>>,
/// Logical agent names that were running at the last broad-scope
/// `hivectl stop`. A subsequent broad-scope `hivectl start` restores
/// only this set (intersected with the requested scope) rather than
/// every configured container, so agents the operator intentionally
/// left stopped stay stopped. `None` when no broad stop has happened
/// since the last start (or since daemon boot) — start then falls
/// back to "start all". In-daemon memory only (hive-c0re survives
/// `hivectl stop`); host-reboot persistence is a separate follow-up.
last_stopped_running: Mutex<Option<Vec<String>>>,
/// Unified wire-facing event channel feeding the dashboard SSE
/// stream. Carries broker messages (mirrored from `broker.subscribe`
/// by the forwarder task in `main.rs`) and dashboard-only mutation
@ -457,6 +466,7 @@ impl Coordinator {
recent_transient: Mutex::new(HashMap::new()),
recent_crashes: Mutex::new(HashMap::new()),
graceful_stop_pending: Mutex::new(HashSet::new()),
last_stopped_running: Mutex::new(None),
dashboard_events,
event_seq: AtomicU64::new(0),
meta_updates_active: AtomicU64::new(0),
@ -1157,6 +1167,20 @@ impl Coordinator {
self.graceful_stop_pending.lock().unwrap().remove(name);
}
/// Record the set of agents that were running at a broad-scope
/// `hivectl stop`, so the next broad-scope `start` restores exactly
/// this set. See the `last_stopped_running` field doc.
pub fn set_last_stopped_running(&self, agents: Vec<String>) {
*self.last_stopped_running.lock().unwrap() = Some(agents);
}
/// Take (and clear) the recorded broad-stop running set, if any. A
/// broad-scope `start` uses this to restore only the previously
/// running agents; `None` means "no record — start all".
pub fn take_last_stopped_running(&self) -> Option<Vec<String>> {
self.last_stopped_running.lock().unwrap().take()
}
/// Set of agents whose transient was cleared within the last
/// `grace` seconds — i.e. agents the operator just acted on,
/// whose stop the crash watcher should NOT classify as a crash.