Skip to content
Merged
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
6 changes: 6 additions & 0 deletions include/envoy/upstream/upstream.h
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,7 @@ class PrioritySet {
COUNTER(upstream_cx_http2_total) \
COUNTER(upstream_cx_idle_timeout) \
COUNTER(upstream_cx_max_requests) \
COUNTER(upstream_cx_max_duration) \
COUNTER(upstream_cx_none_healthy) \
COUNTER(upstream_cx_overflow) \
COUNTER(upstream_cx_pool_overflow) \
Expand Down Expand Up @@ -706,6 +707,11 @@ class ClusterInfo {
*/
virtual const absl::optional<std::chrono::milliseconds> idleTimeout() const PURE;

/**
* @return the max duration for upstream connection pool connections.
*/
virtual const absl::optional<std::chrono::milliseconds> maxConnectionDuration() const PURE;

/**
* @return soft limit on size of the cluster's connections read and write buffers.
*/
Expand Down
15 changes: 14 additions & 1 deletion source/common/conn_pool/conn_pool_base.cc
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,11 @@ ActiveClient::ActiveClient(ConnPoolImplBase& parent, uint64_t lifetime_request_l
conn_length_ = std::make_unique<Stats::HistogramCompletableTimespanImpl>(
parent_.host()->cluster().stats().upstream_cx_length_ms_, parent_.dispatcher().timeSource());
connect_timer_->enableTimer(parent_.host()->cluster().connectTimeout());

const auto max_connection_duration = parent_.host()->cluster().maxConnectionDuration();
if (max_connection_duration) {
lifetime_timer_ = parent_.dispatcher().createTimer([this]() -> void { onLifetimeTimeout(); });
lifetime_timer_->enableTimer(max_connection_duration.value());
}
parent_.host()->stats().cx_total_.inc();
parent_.host()->stats().cx_active_.inc();
parent_.host()->cluster().stats().upstream_cx_total_.inc();
Expand Down Expand Up @@ -424,5 +428,14 @@ void ActiveClient::onConnectTimeout() {
close();
}

void ActiveClient::onLifetimeTimeout() {
if (state_ != ActiveClient::State::CLOSED) {
ENVOY_CONN_LOG(debug, "lifetime timeout, DRAINING", *this);
parent_.host()->cluster().stats().upstream_cx_max_duration_.inc();
parent_.transitionActiveClientState(*this,
Envoy::ConnectionPool::ActiveClient::State::DRAINING);
}
}

} // namespace ConnectionPool
} // namespace Envoy
5 changes: 5 additions & 0 deletions source/common/conn_pool/conn_pool_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ class ActiveClient : public LinkedObject<ActiveClient>,
// Called if the connection does not complete within the cluster's connectTimeout()
void onConnectTimeout();

// Called if the maximum connection duration is reached. If set, this puts an upper
// bound on the lifetime of any connection.
void onLifetimeTimeout();

// Returns the concurrent request limit, accounting for if the total request limit
// is less than the concurrent request limit.
uint64_t effectiveConcurrentRequestLimit() const {
Expand Down Expand Up @@ -74,6 +78,7 @@ class ActiveClient : public LinkedObject<ActiveClient>,
Stats::TimespanPtr conn_connect_ms_;
Stats::TimespanPtr conn_length_;
Event::TimerPtr connect_timer_;
Event::TimerPtr lifetime_timer_;
bool resources_released_{false};
bool timed_out_{false};
};
Expand Down
10 changes: 10 additions & 0 deletions source/common/upstream/upstream_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -789,6 +789,16 @@ ClusterInfoImpl::ClusterInfoImpl(
idle_timeout_ = std::chrono::hours(1);
}

if (config.common_http_protocol_options().has_max_connection_duration()) {
max_connection_duration_ = std::chrono::milliseconds(DurationUtil::durationToMilliseconds(
config.common_http_protocol_options().max_connection_duration()));
if (max_connection_duration_.value().count() == 0) {
max_connection_duration_ = absl::nullopt;
}
} else {
max_connection_duration_ = absl::nullopt;
}

if (config.has_eds_cluster_config()) {
if (config.type() != envoy::config::cluster::v3::Cluster::EDS) {
throw EnvoyException("eds_cluster_config set in a non-EDS cluster");
Expand Down
4 changes: 4 additions & 0 deletions source/common/upstream/upstream_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,9 @@ class ClusterInfoImpl : public ClusterInfo, protected Logger::Loggable<Logger::I
const absl::optional<std::chrono::milliseconds> idleTimeout() const override {
return idle_timeout_;
}
const absl::optional<std::chrono::milliseconds> maxConnectionDuration() const override {
return max_connection_duration_;
}
uint32_t perConnectionBufferLimitBytes() const override {
return per_connection_buffer_limit_bytes_;
}
Expand Down Expand Up @@ -629,6 +632,7 @@ class ClusterInfoImpl : public ClusterInfo, protected Logger::Loggable<Logger::I
const uint32_t max_response_headers_count_;
const std::chrono::milliseconds connect_timeout_;
absl::optional<std::chrono::milliseconds> idle_timeout_;
absl::optional<std::chrono::milliseconds> max_connection_duration_;
const uint32_t per_connection_buffer_limit_bytes_;
TransportSocketMatcherPtr socket_matcher_;
Stats::ScopePtr stats_scope_;
Expand Down
1 change: 1 addition & 0 deletions test/common/http/http1/conn_pool_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ class ConnPoolImplForTest : public ConnPoolImpl {
Network::MockClientConnection* connection_;
CodecClient* codec_client_;
Event::MockTimer* connect_timer_;
Event::MockTimer* lifetime_timer_;
Event::DispatcherPtr client_dispatcher_;
};

Expand Down
9 changes: 9 additions & 0 deletions test/mocks/upstream/cluster_info.cc
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ MockIdleTimeEnabledClusterInfo::MockIdleTimeEnabledClusterInfo() {

MockIdleTimeEnabledClusterInfo::~MockIdleTimeEnabledClusterInfo() = default;

MockMaxConnectionDurationEnabledClusterInfo::MockMaxConnectionDurationEnabledClusterInfo() {
ON_CALL(*this, maxConnectionDuration()).WillByDefault(Return(std::chrono::milliseconds(1000)));
}

MockMaxConnectionDurationEnabledClusterInfo::~MockMaxConnectionDurationEnabledClusterInfo() =
default;

MockClusterInfo::MockClusterInfo()
: http2_options_(::Envoy::Http2::Utility::initializeAndValidateOptions(
envoy::config::core::v3::Http2ProtocolOptions())),
Expand All @@ -51,6 +58,8 @@ MockClusterInfo::MockClusterInfo()
circuit_breakers_stats_, absl::nullopt, absl::nullopt)) {
ON_CALL(*this, connectTimeout()).WillByDefault(Return(std::chrono::milliseconds(1)));
ON_CALL(*this, idleTimeout()).WillByDefault(Return(absl::optional<std::chrono::milliseconds>()));
ON_CALL(*this, maxConnectionDuration())
.WillByDefault(Return(absl::optional<std::chrono::milliseconds>()));
ON_CALL(*this, name()).WillByDefault(ReturnRef(name_));
ON_CALL(*this, edsServiceName()).WillByDefault(ReturnPointee(&eds_service_name_));
ON_CALL(*this, http1Settings()).WillByDefault(ReturnRef(http1_settings_));
Expand Down
7 changes: 7 additions & 0 deletions test/mocks/upstream/cluster_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ class MockClusterInfo : public ClusterInfo {
MOCK_METHOD(bool, addedViaApi, (), (const));
MOCK_METHOD(std::chrono::milliseconds, connectTimeout, (), (const));
MOCK_METHOD(const absl::optional<std::chrono::milliseconds>, idleTimeout, (), (const));
MOCK_METHOD(const absl::optional<std::chrono::milliseconds>, maxConnectionDuration, (), (const));
MOCK_METHOD(uint32_t, perConnectionBufferLimitBytes, (), (const));
MOCK_METHOD(uint64_t, features, (), (const));
MOCK_METHOD(const Http::Http1Settings&, http1Settings, (), (const));
Expand Down Expand Up @@ -181,5 +182,11 @@ class MockIdleTimeEnabledClusterInfo : public MockClusterInfo {
~MockIdleTimeEnabledClusterInfo() override;
};

class MockMaxConnectionDurationEnabledClusterInfo : public MockClusterInfo {
public:
MockMaxConnectionDurationEnabledClusterInfo();
~MockMaxConnectionDurationEnabledClusterInfo() override;
};

} // namespace Upstream
} // namespace Envoy