Files
RustProxy/src/runtime/docker.rs
T
2026-10-04 11:15:58 +02:00

54 lines
2.0 KiB
Rust

impl App {
/// Rebuild only the effective routing snapshot from the latest Docker observations.
/// Desired configuration and its SQLite revision remain unchanged.
pub async fn reconcile_docker(self: &Arc<Self>) -> Result<(), ApiError> {
let _lock = self.update_lock.lock().await;
let previous = self.config.load_full();
let desired = previous.envelope.config.clone();
let desired_vhost_count = desired.vhosts.len();
let observed = self.docker.snapshot().await;
let policy = self.policy.clone();
let defaults = self.startup_listeners;
let active_listeners = self.active_listeners.clone();
let revision = previous.envelope.revision;
let prepared = tokio::task::spawn_blocking(move || {
let effective = crate::docker::effective_config(desired, &observed)?;
let mut prepared = config::compile_with_active(
effective,
revision,
&policy,
defaults,
Some(&previous),
&active_listeners,
)?;
prepared
.envelope
.config
.vhosts
.truncate(desired_vhost_count);
Ok::<_, anyhow::Error>(prepared)
})
.await
.map_err(|_| {
ApiError(
StatusCode::INTERNAL_SERVER_ERROR,
"Docker reconcile task failed".into(),
)
})?
.map_err(|error| ApiError(StatusCode::UNPROCESSABLE_ENTITY, format!("{error:#}")))?;
self.config.store(Arc::new(prepared));
Ok(())
}
pub async fn refresh_docker(
self: &Arc<Self>,
) -> Result<Vec<crate::docker::Observation>, ApiError> {
let settings = self.config.load().envelope.config.docker_agents.clone();
let (observations, changed) = self.docker.refresh(&settings, true).await;
if changed {
self.reconcile_docker().await?;
}
Ok(observations)
}
}