missions: wire per-mission runtime container into launch + retry (C3 slice 2)
- mission_orchestrator::on_launch now calls ensure_container after the repo checkout, persists the container_name + endpoint on the missions row. Non-fatal — logs and continues on docker errors so dev-mode + tests keep working. - phase_runner::launch_phase does the same as a fallback for any mission whose runtime_endpoint is null (pre-C3 or torn down). Nothing reads the endpoint yet; slice 3 swaps topology_worker over.
This commit is contained in:
@@ -65,6 +65,43 @@ pub async fn on_launch(
|
|||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Provision the per-mission ZeroClaw runtime container (C3).
|
||||||
|
// Idempotent: returns the endpoint if the container is already
|
||||||
|
// running. Falls back silently when docker is unreachable so
|
||||||
|
// dev-mode + tests still work — the topology_worker will use the
|
||||||
|
// shared runtime endpoint in that case.
|
||||||
|
if let Some(prov) = crate::mission_runtime::MissionRuntimeProvisioner::from_env() {
|
||||||
|
match prov.ensure_container(mission_id).await {
|
||||||
|
Ok(endpoint) => {
|
||||||
|
let container_name = crate::mission_runtime::container_name(mission_id);
|
||||||
|
if let Err(e) = cm_db::repo::missions::set_runtime_binding(
|
||||||
|
pool,
|
||||||
|
mission_id,
|
||||||
|
workspace_id.as_uuid(),
|
||||||
|
Some(&container_name),
|
||||||
|
Some(&endpoint),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
eprintln!(
|
||||||
|
"mission_orchestrator: bind runtime container for {mission_id} failed: {e}"
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
eprintln!(
|
||||||
|
"mission_orchestrator: runtime container {container_name} → {endpoint} for mission {mission_id}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => eprintln!(
|
||||||
|
"mission_orchestrator: provision runtime container for {mission_id} failed (continuing with shared runtime): {e}"
|
||||||
|
),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
eprintln!(
|
||||||
|
"mission_orchestrator: docker unreachable, mission {mission_id} will use shared runtime"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Skip team materialization if already bound.
|
// Skip team materialization if already bound.
|
||||||
if mission.team_id.is_some() {
|
if mission.team_id.is_some() {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
|
|||||||
@@ -142,6 +142,44 @@ async fn launch_phase(
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Provision the per-mission runtime container if it isn't already
|
||||||
|
// bound. Idempotent — on_launch sets this on initial launch, but
|
||||||
|
// pre-C3 missions or retries against a torn-down container land
|
||||||
|
// here. Non-fatal: if docker is unreachable the run falls back to
|
||||||
|
// the shared runtime.
|
||||||
|
let mission = cm_db::repo::missions::get(
|
||||||
|
pool,
|
||||||
|
mission_id,
|
||||||
|
workspace_id,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(|e| format!("load mission for runtime binding: {e}"))?;
|
||||||
|
if let Some(m) = mission {
|
||||||
|
if m.runtime_endpoint.is_none() {
|
||||||
|
if let Some(prov) = crate::mission_runtime::MissionRuntimeProvisioner::from_env() {
|
||||||
|
match prov.ensure_container(mission_id).await {
|
||||||
|
Ok(endpoint) => {
|
||||||
|
let name = crate::mission_runtime::container_name(mission_id);
|
||||||
|
if let Err(e) = cm_db::repo::missions::set_runtime_binding(
|
||||||
|
pool,
|
||||||
|
mission_id,
|
||||||
|
workspace_id,
|
||||||
|
Some(&name),
|
||||||
|
Some(&endpoint),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
eprintln!("phase_runner: bind runtime container for {mission_id} failed: {e}");
|
||||||
|
} else {
|
||||||
|
eprintln!("phase_runner: runtime container {name} → {endpoint} for mission {mission_id}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => eprintln!("phase_runner: provision runtime container for {mission_id} failed (continuing): {e}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Ensure the mission's repo is checked out before firing any run.
|
// Ensure the mission's repo is checked out before firing any run.
|
||||||
// Idempotent: fetch+reset on existing clones, clone on missing.
|
// Idempotent: fetch+reset on existing clones, clone on missing.
|
||||||
// Runs on EVERY phase launch — including retries — so a retry
|
// Runs on EVERY phase launch — including retries — so a retry
|
||||||
|
|||||||
Reference in New Issue
Block a user