From 4346007d37df2e9feb60bd002b0916bae2010169 Mon Sep 17 00:00:00 2001 From: archipelago Date: Tue, 23 Jun 2026 14:40:48 -0400 Subject: [PATCH] fix(orchestrator): only TCP host ports get reachability-probed wait_for_manifest_host_ports TCP-connect-probed every published port, including UDP/SCTP. netbird's 3478/udp STUN can never answer a TCP connect, so the probe failed forever and drove an endless host-port repair/reconcile loop on .228 (netbird-server restarting ~every 60s). Filter to tcp (empty protocol = tcp). Co-Authored-By: Claude Opus 4.8 (1M context) --- core/archipelago/src/container/prod_orchestrator.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/core/archipelago/src/container/prod_orchestrator.rs b/core/archipelago/src/container/prod_orchestrator.rs index 26d9852f..73c0ffa6 100644 --- a/core/archipelago/src/container/prod_orchestrator.rs +++ b/core/archipelago/src/container/prod_orchestrator.rs @@ -469,7 +469,18 @@ async fn http_host_port_ready(port: u16, path: &str) -> bool { } async fn wait_for_manifest_host_ports(manifest: &AppManifest, timeout_secs: u64) -> Result<()> { - for port in manifest.app.ports.iter().map(|p| p.host) { + // Only TCP host ports are reachability-probed: the probe is a TCP connect, + // which a UDP/SCTP listener (e.g. netbird's 3478/udp STUN) can never answer, + // so probing it would always "fail" and drive an endless host-port repair + // loop (observed on .228 after netbird's manifest deploy). Default protocol + // (empty) is tcp. + for port in manifest + .app + .ports + .iter() + .filter(|p| matches!(p.protocol.to_ascii_lowercase().as_str(), "" | "tcp")) + .map(|p| p.host) + { let ready = match manifest.app.id.as_str() { "uptime-kuma" => wait_for_http_host_port(port, "/", timeout_secs).await, _ => wait_for_host_port(port, timeout_secs).await,