From d1daa97ac5562ceb9539b2567a26d490be048b9d Mon Sep 17 00:00:00 2001 From: houseme Date: Fri, 10 Jul 2026 09:34:10 +0800 Subject: [PATCH] fix(ecstore): keep local path startup fail-fast under Kubernetes (#4640) The startup topology convergence auto-detection (added in #4631) checked Kubernetes before endpoint style, so a local path deployment (single or multi-drive, non-distributed) running inside Kubernetes was classified as orchestrated with an effectively unbounded wait window. Path-style endpoints have no hostnames to resolve, so the wait never actually triggers and runtime behavior is unchanged, but the startup log then advertised mode=orchestrated / wait_timeout=MAX for a purely local deployment, which is misleading and contradicts the documented policy (local path endpoints -> fail-fast). Order the auto-detection by endpoint style first: only distributed URL endpoints, which resolve hostnames, pick orchestrated (Kubernetes) or bounded (otherwise); local path endpoints stay fail-fast regardless of the platform. Update the doc comment to match and add a policy case locking Kubernetes + local path to fail-fast. Co-authored-by: heihutu --- crates/config/src/constants/app.rs | 4 ++-- crates/ecstore/src/layout/endpoints.rs | 19 ++++++++++++++----- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/crates/config/src/constants/app.rs b/crates/config/src/constants/app.rs index 375efbdd4..405bb7345 100644 --- a/crates/config/src/constants/app.rs +++ b/crates/config/src/constants/app.rs @@ -153,8 +153,8 @@ pub const DEFAULT_UNSAFE_BYPASS_DISK_CHECK: bool = false; /// - `bounded`: wait for a finite window (see /// `ENV_STARTUP_TOPOLOGY_WAIT_TIMEOUT`) then fail with an actionable error. /// - `fail-fast`: fail on the first non-transient resolution error (CI/local). -/// - `auto`: Kubernetes -> orchestrated, distributed URL endpoints -> bounded, -/// local path endpoints -> fail-fast. +/// - `auto`: distributed URL endpoints use orchestrated on Kubernetes and +/// bounded otherwise; local path endpoints use fail-fast (no DNS to await). pub const ENV_STARTUP_TOPOLOGY_WAIT_MODE: &str = "RUSTFS_STARTUP_TOPOLOGY_WAIT_MODE"; /// Environment variable bounding how long startup waits for topology/DNS diff --git a/crates/ecstore/src/layout/endpoints.rs b/crates/ecstore/src/layout/endpoints.rs index 35ac3bbe4..62ce20e9a 100644 --- a/crates/ecstore/src/layout/endpoints.rs +++ b/crates/ecstore/src/layout/endpoints.rs @@ -768,13 +768,16 @@ impl StartupTopologyPolicy { Some("bounded") => StartupTopologyWaitMode::Bounded, Some("fail-fast") | Some("failfast") | Some("strict") => StartupTopologyWaitMode::FailFast, // "auto", unset, or unrecognized: derive from the environment. + // Only URL-style (distributed) endpoints resolve hostnames and need + // to wait for DNS/topology convergence; local path endpoints never + // do, so they fail fast regardless of the platform. _ => { - if kubernetes { - StartupTopologyWaitMode::Orchestrated - } else if distributed { - StartupTopologyWaitMode::Bounded - } else { + if !distributed { StartupTopologyWaitMode::FailFast + } else if kubernetes { + StartupTopologyWaitMode::Orchestrated + } else { + StartupTopologyWaitMode::Bounded } } }; @@ -1351,6 +1354,12 @@ mod test { let local = StartupTopologyPolicy::resolve_from(None, false, false, None, None); assert_eq!(local.mode, StartupTopologyWaitMode::FailFast); assert_eq!(local.wait_timeout, Duration::ZERO); + + // Local path endpoints stay fail-fast even under Kubernetes: they have + // no hostnames to resolve, so there is nothing to wait for. + let k8s_local = StartupTopologyPolicy::resolve_from(None, true, false, None, None); + assert_eq!(k8s_local.mode, StartupTopologyWaitMode::FailFast); + assert_eq!(k8s_local.wait_timeout, Duration::ZERO); } #[test]