use std::time::Duration;
use tracing::info;
use orca_core::runtime::Runtime;
use crate::state::AppState;
const GRACEFUL_TIMEOUT: Duration = Duration::from_secs(5);
pub(crate) async fn canary_deploy(
state: &AppState,
runtime: &dyn Runtime,
config: &orca_core::config::ServiceConfig,
spec: &orca_core::types::WorkloadSpec,
desired: u32,
) -> anyhow::Result<()> {
for i in 0..desired {
let mut replica_spec = spec.clone();
replica_spec.name = format!("{}-canary-{i}", spec.name);
match crate::instance::create_and_start_instance(runtime, &replica_spec).await {
Ok(mut instance) => {
instance.is_canary = true;
let mut services = state.services.write().await;
if let Some(svc) = services.get_mut(&config.name) {
svc.instances.push(instance);
}
}
Err(e) => {
tracing::error!("Canary instance {}-canary-{i} failed: {e}", config.name);
}
}
}
match config.runtime {
orca_core::types::RuntimeKind::Container => {
crate::routes::update_container_routes(state, config).await;
}
orca_core::types::RuntimeKind::Wasm => {
crate::routes::update_wasm_triggers(state, config).await;
}
}
info!("Canary deploy complete for {}", config.name);
Ok(())
}
pub async fn promote(state: &AppState, service_name: &str) -> anyhow::Result<()> {
let runtime_kind = {
let services = state.services.read().await;
let svc = services
.get(service_name)
.ok_or_else(|| anyhow::anyhow!("service '{}' not found", service_name))?;
svc.config.runtime
};
let runtime = crate::reconciler::get_runtime(state, runtime_kind)?;
let mut services = state.services.write().await;
let svc = services
.get_mut(service_name)
.ok_or_else(|| anyhow::anyhow!("service '{}' not found", service_name))?;
let (canary, stable): (Vec<_>, Vec<_>) = svc.instances.drain(..).partition(|i| i.is_canary);
if canary.is_empty() {
svc.instances = stable;
anyhow::bail!("no canary instances to promote for '{service_name}'");
}
for instance in &stable {
let _ = runtime.stop(&instance.handle, GRACEFUL_TIMEOUT).await;
let _ = runtime.remove(&instance.handle).await;
}
for mut instance in canary {
instance.is_canary = false;
svc.instances.push(instance);
}
let config = svc.config.clone();
drop(services);
crate::routes::update_container_routes(state, &config).await;
info!("Promoted canary to stable for {service_name}");
Ok(())
}