hivectl: resolve stop/start scope to names at the c0re entry point
Per review: c0re expands the LifecycleScope to explicit container-name lists (scoped_agents / scoped_infra) in the dispatch arm, then hands those lists to handle_stop / handle_start. The 'all agents' flag no longer flows past the resolution boundary, so downstream consumers (incl. the future graceful-stop queue) always operate on concrete names. CLI --agents flag unchanged.
This commit is contained in:
parent
465dd2d433
commit
c673dce73d
1 changed files with 36 additions and 22 deletions
|
|
@ -94,8 +94,20 @@ async fn dispatch(req: &HostRequest, coord: Arc<Coordinator>) -> HostResponse {
|
||||||
HostResponse::success()
|
HostResponse::success()
|
||||||
}
|
}
|
||||||
HostRequest::RestartAll => handle_restart_all().await?,
|
HostRequest::RestartAll => handle_restart_all().await?,
|
||||||
HostRequest::Stop { scope, graceful } => handle_stop(scope, *graceful).await?,
|
HostRequest::Stop { scope, graceful } => {
|
||||||
HostRequest::Start { scope } => handle_start(scope).await?,
|
// Resolve the scope to explicit container names at the entry
|
||||||
|
// point, then operate on names — never pass the bare "all
|
||||||
|
// agents" flag deeper (it'd force every consumer, incl. the
|
||||||
|
// graceful-stop queue, to re-expand it).
|
||||||
|
let agents = scoped_agents(scope).await?;
|
||||||
|
let infra = scoped_infra(scope);
|
||||||
|
handle_stop(&agents, &infra, *graceful).await?
|
||||||
|
}
|
||||||
|
HostRequest::Start { scope } => {
|
||||||
|
let agents = scoped_agents(scope).await?;
|
||||||
|
let infra = scoped_infra(scope);
|
||||||
|
handle_start(&agents, &infra).await?
|
||||||
|
}
|
||||||
HostRequest::Destroy { name, purge } => {
|
HostRequest::Destroy { name, purge } => {
|
||||||
actions::destroy(&coord, name, *purge).await?;
|
actions::destroy(&coord, name, *purge).await?;
|
||||||
HostResponse::success()
|
HostResponse::success()
|
||||||
|
|
@ -202,24 +214,25 @@ async fn handle_restart_all() -> Result<HostResponse> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stop the containers a [`LifecycleScope`] selects (`hivectl stop`): the
|
/// Stop the given `agents` (resolved logical names) then `infra` containers
|
||||||
/// scoped sub-agents, then the scoped infra containers. Agents go down
|
/// (`hivectl stop`). Agents go down before infra so they're not mid-request
|
||||||
/// before infra so they're not mid-request against a forge/matrix that's
|
/// against a forge/matrix that's already gone. Per-target failures are
|
||||||
/// already gone. Per-target failures are aggregated rather than aborting on
|
/// aggregated rather than aborting on the first error, mirroring
|
||||||
/// the first error, mirroring `handle_restart_all`.
|
/// `handle_restart_all`. Callers resolve the [`LifecycleScope`] to these
|
||||||
async fn handle_stop(scope: &LifecycleScope, graceful: bool) -> Result<HostResponse> {
|
/// explicit name lists up front — this never sees the "all" flag.
|
||||||
tracing::info!(?scope, graceful, "stop");
|
async fn handle_stop(agents: &[String], infra: &[&str], graceful: bool) -> Result<HostResponse> {
|
||||||
|
tracing::info!(?agents, ?infra, graceful, "stop");
|
||||||
let mut ok_items: Vec<String> = Vec::new();
|
let mut ok_items: Vec<String> = Vec::new();
|
||||||
let mut errors: Vec<String> = Vec::new();
|
let mut errors: Vec<String> = Vec::new();
|
||||||
|
|
||||||
for agent in scoped_agents(scope).await? {
|
for agent in agents {
|
||||||
// TODO(graceful agent stop): when `graceful`, run the per-agent
|
// TODO(graceful agent stop): when `graceful`, run the per-agent
|
||||||
// quiesce (turn-end → drain → reject new messages) before the kill.
|
// quiesce (turn-end → drain → reject new messages) before the kill.
|
||||||
// The flag is threaded through the wire now; the quiesce itself
|
// The flag is threaded through the wire now; the quiesce itself
|
||||||
// lands with the graceful-agent-stop work.
|
// lands with the graceful-agent-stop work.
|
||||||
let _ = graceful;
|
let _ = graceful;
|
||||||
match lifecycle::kill(&agent).await {
|
match lifecycle::kill(agent).await {
|
||||||
Ok(()) => ok_items.push(agent),
|
Ok(()) => ok_items.push(agent.clone()),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
tracing::warn!(%agent, error = ?e, "stop: agent kill failed");
|
tracing::warn!(%agent, error = ?e, "stop: agent kill failed");
|
||||||
errors.push(format!("{agent}: {e:#}"));
|
errors.push(format!("{agent}: {e:#}"));
|
||||||
|
|
@ -227,7 +240,7 @@ async fn handle_stop(scope: &LifecycleScope, graceful: bool) -> Result<HostRespo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for container in scoped_infra(scope) {
|
for &container in infra {
|
||||||
match crate::priv_client::control_infra_container(container, InfraAction::Stop).await {
|
match crate::priv_client::control_infra_container(container, InfraAction::Stop).await {
|
||||||
Ok(()) => ok_items.push(container.to_owned()),
|
Ok(()) => ok_items.push(container.to_owned()),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
|
@ -240,15 +253,16 @@ async fn handle_stop(scope: &LifecycleScope, graceful: bool) -> Result<HostRespo
|
||||||
Ok(finish_lifecycle(ok_items, &errors))
|
Ok(finish_lifecycle(ok_items, &errors))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start the containers a [`LifecycleScope`] selects (`hivectl start`) —
|
/// Start the given `infra` containers then `agents` (`hivectl start`) — the
|
||||||
/// the inverse of [`handle_stop`]. Infra comes up before agents so the
|
/// inverse of [`handle_stop`]. Infra comes up before agents so the agents
|
||||||
/// agents find forge/matrix/gateway ready. Per-target failures aggregated.
|
/// find forge/matrix/gateway ready. Per-target failures aggregated. Callers
|
||||||
async fn handle_start(scope: &LifecycleScope) -> Result<HostResponse> {
|
/// resolve the [`LifecycleScope`] to these explicit name lists up front.
|
||||||
tracing::info!(?scope, "start");
|
async fn handle_start(agents: &[String], infra: &[&str]) -> Result<HostResponse> {
|
||||||
|
tracing::info!(?agents, ?infra, "start");
|
||||||
let mut ok_items: Vec<String> = Vec::new();
|
let mut ok_items: Vec<String> = Vec::new();
|
||||||
let mut errors: Vec<String> = Vec::new();
|
let mut errors: Vec<String> = Vec::new();
|
||||||
|
|
||||||
for container in scoped_infra(scope) {
|
for &container in infra {
|
||||||
match crate::priv_client::control_infra_container(container, InfraAction::Start).await {
|
match crate::priv_client::control_infra_container(container, InfraAction::Start).await {
|
||||||
Ok(()) => ok_items.push(container.to_owned()),
|
Ok(()) => ok_items.push(container.to_owned()),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
|
@ -258,9 +272,9 @@ async fn handle_start(scope: &LifecycleScope) -> Result<HostResponse> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for agent in scoped_agents(scope).await? {
|
for agent in agents {
|
||||||
match lifecycle::start(&agent).await {
|
match lifecycle::start(agent).await {
|
||||||
Ok(()) => ok_items.push(agent),
|
Ok(()) => ok_items.push(agent.clone()),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
tracing::warn!(%agent, error = ?e, "start: agent start failed");
|
tracing::warn!(%agent, error = ?e, "start: agent start failed");
|
||||||
errors.push(format!("{agent}: {e:#}"));
|
errors.push(format!("{agent}: {e:#}"));
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue