Skip to content

Commit 6dd4b6f

Browse files
authored
health check: fix additional regression from #6765 (#6942)
If we inline delete a host during a failure callback we need to account for the connection being cleaned up prior to handling 'connection: close' headers. Signed-off-by: Matt Klein <[email protected]>
1 parent 4b0b654 commit 6dd4b6f

File tree

4 files changed

+38
-14
lines changed

4 files changed

+38
-14
lines changed

source/common/upstream/health_checker_impl.cc

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,8 @@ void HttpHealthCheckerImpl::HttpActiveHealthCheckSession::onInterval() {
195195
expect_reset_ = false;
196196
}
197197

198-
request_encoder_ = &client_->newStream(*this);
199-
request_encoder_->getStream().addCallbacks(*this);
198+
Http::StreamEncoder* request_encoder = &client_->newStream(*this);
199+
request_encoder->getStream().addCallbacks(*this);
200200

201201
Http::HeaderMapImpl request_headers{
202202
{Http::Headers::get().Method, "GET"},
@@ -209,8 +209,7 @@ void HttpHealthCheckerImpl::HttpActiveHealthCheckSession::onInterval() {
209209
stream_info.setDownstreamRemoteAddress(local_address_);
210210
stream_info.onUpstreamHostSelected(host_);
211211
parent_.request_headers_parser_->evaluateHeaders(request_headers, stream_info);
212-
request_encoder_->encodeHeaders(request_headers, true);
213-
request_encoder_ = nullptr;
212+
request_encoder->encodeHeaders(request_headers, true);
214213
}
215214

216215
void HttpHealthCheckerImpl::HttpActiveHealthCheckSession::onResetStream(Http::StreamResetReason,
@@ -269,13 +268,16 @@ void HttpHealthCheckerImpl::HttpActiveHealthCheckSession::onResponseComplete() {
269268
break;
270269
}
271270

272-
if ((response_headers_->Connection() &&
273-
absl::EqualsIgnoreCase(response_headers_->Connection()->value().getStringView(),
274-
Http::Headers::get().ConnectionValues.Close)) ||
275-
(response_headers_->ProxyConnection() && protocol_ != Http::Protocol::Http2 &&
276-
absl::EqualsIgnoreCase(response_headers_->ProxyConnection()->value().getStringView(),
277-
Http::Headers::get().ConnectionValues.Close)) ||
278-
!parent_.reuse_connection_) {
271+
// It is possible for this session to have been deferred destroyed inline in handleFailure()
272+
// above so make sure we still have a connection that we might need to close.
273+
if (client_ != nullptr &&
274+
((response_headers_->Connection() &&
275+
absl::EqualsIgnoreCase(response_headers_->Connection()->value().getStringView(),
276+
Http::Headers::get().ConnectionValues.Close)) ||
277+
(response_headers_->ProxyConnection() && protocol_ != Http::Protocol::Http2 &&
278+
absl::EqualsIgnoreCase(response_headers_->ProxyConnection()->value().getStringView(),
279+
Http::Headers::get().ConnectionValues.Close)) ||
280+
!parent_.reuse_connection_)) {
279281
client_->close();
280282
}
281283

source/common/upstream/health_checker_impl.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,6 @@ class HttpHealthCheckerImpl : public HealthCheckerImplBase {
111111
ConnectionCallbackImpl connection_callback_impl_{*this};
112112
HttpHealthCheckerImpl& parent_;
113113
Http::CodecClientPtr client_;
114-
Http::StreamEncoder* request_encoder_{};
115114
Http::HeaderMapPtr response_headers_;
116115
const std::string& hostname_;
117116
const Http::Protocol protocol_;

test/common/upstream/health_checker_impl_test.cc

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1271,7 +1271,7 @@ TEST_F(HttpHealthCheckerImplTest, SuccessStartFailedFailFirstLogError) {
12711271
}
12721272

12731273
// Verify that removal during a failure callback works.
1274-
TEST_F(HttpHealthCheckerImplTest, HttpFailRemoveHostInCallback) {
1274+
TEST_F(HttpHealthCheckerImplTest, HttpFailRemoveHostInCallbackNoClose) {
12751275
setupNoServiceValidationHC();
12761276
cluster_->prioritySet().getMockHostSet(0)->hosts_ = {
12771277
makeTestHost(cluster_->info_, "tcp://127.0.0.1:80")};
@@ -1292,6 +1292,28 @@ TEST_F(HttpHealthCheckerImplTest, HttpFailRemoveHostInCallback) {
12921292
respond(0, "503", false);
12931293
}
12941294

1295+
// Verify that removal during a failure callback works with connection close.
1296+
TEST_F(HttpHealthCheckerImplTest, HttpFailRemoveHostInCallbackClose) {
1297+
setupNoServiceValidationHC();
1298+
cluster_->prioritySet().getMockHostSet(0)->hosts_ = {
1299+
makeTestHost(cluster_->info_, "tcp://127.0.0.1:80")};
1300+
expectSessionCreate();
1301+
expectStreamCreate(0);
1302+
EXPECT_CALL(*test_sessions_[0]->timeout_timer_, enableTimer(_));
1303+
health_checker_->start();
1304+
1305+
EXPECT_CALL(*this, onHostStatus(_, HealthTransition::Changed))
1306+
.WillOnce(Invoke([&](HostSharedPtr host, HealthTransition) {
1307+
cluster_->prioritySet().getMockHostSet(0)->hosts_ = {};
1308+
cluster_->prioritySet().runUpdateCallbacks(0, {}, {host});
1309+
}));
1310+
EXPECT_CALL(*event_logger_, logEjectUnhealthy(_, _, _));
1311+
EXPECT_CALL(*test_sessions_[0]->interval_timer_, enableTimer(_)).Times(0);
1312+
EXPECT_CALL(*test_sessions_[0]->timeout_timer_, disableTimer()).Times(0);
1313+
EXPECT_CALL(*event_logger_, logUnhealthy(_, _, _, true));
1314+
respond(0, "503", true);
1315+
}
1316+
12951317
TEST_F(HttpHealthCheckerImplTest, HttpFail) {
12961318
setupNoServiceValidationHC();
12971319
cluster_->prioritySet().getMockHostSet(0)->hosts_ = {

test/integration/eds_integration_test.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,8 @@ TEST_P(EdsIntegrationTest, RemoveAfterHcFail) {
103103

104104
// Fail HC and verify the host is gone.
105105
waitForNextUpstreamRequest();
106-
upstream_request_->encodeHeaders(Http::TestHeaderMapImpl{{":status", "503"}}, true);
106+
upstream_request_->encodeHeaders(
107+
Http::TestHeaderMapImpl{{":status", "503"}, {"connection", "close"}}, true);
107108
test_server_->waitForGaugeEq("cluster.cluster_0.membership_healthy", 0);
108109
EXPECT_EQ(0, test_server_->gauge("cluster.cluster_0.membership_total")->value());
109110
}

0 commit comments

Comments
 (0)