Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions source/common/init/manager_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class ManagerImpl : public Manager, Logger::Loggable<Logger::Id::init> {
void initialize(const Watcher& watcher) override;
void updateWatcher(const Watcher& watcher) override;
void dumpUnreadyTargets(envoy::admin::v3::UnreadyTargetsDumps& dumps) override;
uint32_t uninitializedCount() const { return count_; }

private:
// Callback function with an additional target_name parameter, decrease unready targets count by
Expand Down
6 changes: 4 additions & 2 deletions source/common/upstream/upstream_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1995,8 +1995,10 @@ absl::Status ClusterImplBase::parseDropOverloadConfig(
void ClusterImplBase::setHealthChecker(const HealthCheckerSharedPtr& health_checker) {
ASSERT(!health_checker_);
health_checker_ = health_checker;
if (!Runtime::runtimeFeatureEnabled(
"envoy.reloadable_features.health_check_after_cluster_warming")) {
const bool defer = Runtime::runtimeFeatureEnabled(
"envoy.reloadable_features.health_check_after_cluster_warming") &&
(!hasZeroInitialFetchTimeout() || init_manager_.uninitializedCount() > 0);
if (!defer) {
health_checker_->start();
}
health_checker_->addHostCheckCompleteCb(
Expand Down
2 changes: 2 additions & 0 deletions source/common/upstream/upstream_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1302,6 +1302,8 @@ class ClusterImplBase : public Cluster, protected Logger::Loggable<Logger::Id::u

virtual void reloadHealthyHostsHelper(const HostSharedPtr& host);

virtual bool hasZeroInitialFetchTimeout() const { return false; }

absl::Status parseDropOverloadConfig(
const envoy::config::endpoint::v3::ClusterLoadAssignment& cluster_load_assignment);

Expand Down
2 changes: 2 additions & 0 deletions source/extensions/clusters/eds/eds.cc
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ EdsClusterImpl::EdsClusterImpl(const envoy::config::cluster::v3::Cluster& cluste
} else {
initialize_phase_ = InitializePhase::Secondary;
}
zero_initial_fetch_timeout_ =
Config::Utility::configSourceInitialFetchTimeout(eds_config).count() == 0;
const auto resource_name = resource_type_helper_.getResourceName();
if (Runtime::runtimeFeatureEnabled(
"envoy.reloadable_features.xdstp_based_config_singleton_subscriptions")) {
Expand Down
4 changes: 4 additions & 0 deletions source/extensions/clusters/eds/eds.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ class EdsClusterImpl : public BaseDynamicClusterImpl,
// ClusterImplBase
void reloadHealthyHostsHelper(const HostSharedPtr& host) override;
void startPreInit() override;
bool hasZeroInitialFetchTimeout() const override { return zero_initial_fetch_timeout_; }
void onAssignmentTimeout();

// Returns true iff all the LEDS based localities were updated.
Expand Down Expand Up @@ -128,6 +129,9 @@ class EdsClusterImpl : public BaseDynamicClusterImpl,

// Tracks whether a cached resource is used as the current EDS resource.
bool using_cached_resource_{false};

// True when the EDS config source has initialFetchTimeout of 0.
bool zero_initial_fetch_timeout_{false};
};

using EdsClusterImplSharedPtr = std::shared_ptr<EdsClusterImpl>;
Expand Down
47 changes: 47 additions & 0 deletions test/extensions/clusters/eds/eds_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3612,6 +3612,53 @@ TEST_F(XdstpConfigsEdsTest, DeltaOnConfigUpdateSuccess) {
.get()
.value());
}

// EDS-only cluster with initialFetchTimeout: 0s.
// Health checks must start immediately — deferring would block them forever.
TEST_F(EdsTest, HealthCheckStartsImmediatelyWithZeroInitialFetchTimeout) {
TestScopedRuntime scoped_runtime;
scoped_runtime.mergeValues(
{{"envoy.reloadable_features.health_check_after_cluster_warming", "true"}});

resetCluster(R"EOF(
name: name
connect_timeout: 0.25s
type: EDS
lb_policy: ROUND_ROBIN
eds_cluster_config:
service_name: fare
eds_config:
initial_fetch_timeout: 0s
api_config_source:
api_type: GRPC
grpc_services:
envoy_grpc:
cluster_name: eds
)EOF",
Cluster::InitializePhase::Secondary);

auto health_checker = std::make_shared<MockHealthChecker>();
EXPECT_CALL(*health_checker, start());
EXPECT_CALL(*health_checker, addHostCheckCompleteCb(_)).Times(1);
cluster_->setHealthChecker(health_checker);
}

// EDS cluster with non-zero initialFetchTimeout.
// Health checks must be deferred until warming completes.
TEST_F(EdsTest, HealthCheckDeferredWithNonZeroInitialFetchTimeout) {
TestScopedRuntime scoped_runtime;
scoped_runtime.mergeValues(
{{"envoy.reloadable_features.health_check_after_cluster_warming", "true"}});

// Default cluster config has no explicit initialFetchTimeout, which defaults to 15s.
resetCluster();

auto health_checker = std::make_shared<MockHealthChecker>();
EXPECT_CALL(*health_checker, start()).Times(0);
EXPECT_CALL(*health_checker, addHostCheckCompleteCb(_)).Times(1);
cluster_->setHealthChecker(health_checker);
}

} // namespace
} // namespace Upstream
} // namespace Envoy
Loading