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
11 changes: 10 additions & 1 deletion source/common/upstream/health_checker_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -714,6 +714,11 @@ void GrpcHealthCheckerImpl::GrpcActiveHealthCheckSession::onResetStream(Http::St
ENVOY_CONN_LOG(debug, "connection/stream error health_flags={}", *client_,
HostUtility::healthFlagsToString(*host_));

if (!parent_.reuse_connection_) {
// Stream reset was unexpected, so we haven't closed the connection yet.
client_->close();
}

// TODO(baranov1ch): according to all HTTP standards, we should check if reason is one of
// Http::StreamResetReason::RemoteRefusedStreamReset (which may mean GOAWAY),
// Http::StreamResetReason::RemoteReset or Http::StreamResetReason::ConnectionTermination (both
Expand Down Expand Up @@ -783,7 +788,11 @@ void GrpcHealthCheckerImpl::GrpcActiveHealthCheckSession::onTimeout() {
ENVOY_CONN_LOG(debug, "connection/stream timeout health_flags={}", *client_,
HostUtility::healthFlagsToString(*host_));
expect_reset_ = true;
request_encoder_->getStream().resetStream(Http::StreamResetReason::LocalReset);
if (!parent_.reuse_connection_) {
client_->close();
} else {
request_encoder_->getStream().resetStream(Http::StreamResetReason::LocalReset);
}
}

void GrpcHealthCheckerImpl::GrpcActiveHealthCheckSession::logHealthCheckStatus(
Expand Down
60 changes: 60 additions & 0 deletions test/common/upstream/health_checker_impl_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4487,6 +4487,66 @@ TEST_F(GrpcHealthCheckerImplTest, DontReuseConnectionBetweenChecks) {
expectHostHealthy(true);
}

// Test that we close connections when a timeout occurs and reuse_connection is false.
TEST_F(GrpcHealthCheckerImplTest, DontReuseConnectionTimeout) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a comment to this test case to make it easier to understand which assertion is verifying that we're not reusing the connection? I think its expectClientCreate but it would be nice with a comment alongside it

setupNoReuseConnectionHC();
cluster_->prioritySet().getMockHostSet(0)->hosts_ = {
makeTestHost(cluster_->info_, "tcp://127.0.0.1:80")};

expectSessionCreate();
expectHealthcheckStart(0);
EXPECT_CALL(event_logger_, logUnhealthy(_, _, _, true));
health_checker_->start();

expectHealthcheckStop(0);
// Timeouts are considered network failures and make host unhealthy also after 2nd event.
EXPECT_CALL(*this, onHostStatus(_, HealthTransition::ChangePending));
test_sessions_[0]->timeout_timer_->invokeCallback();
expectHostHealthy(true);

// A new client is created because we close the connection
// when a timeout occurs and connection reuse is disabled.
expectClientCreate(0);
expectHealthcheckStart(0);
test_sessions_[0]->interval_timer_->invokeCallback();

expectHealthcheckStop(0);
// Test host state haven't changed.
EXPECT_CALL(*this, onHostStatus(_, HealthTransition::Unchanged));
respondServiceStatus(0, grpc::health::v1::HealthCheckResponse::SERVING);
expectHostHealthy(true);
}

// Test that we close connections when a stream reset occurs and reuse_connection is false.
TEST_F(GrpcHealthCheckerImplTest, DontReuseConnectionStreamReset) {
setupNoReuseConnectionHC();
cluster_->prioritySet().getMockHostSet(0)->hosts_ = {
makeTestHost(cluster_->info_, "tcp://127.0.0.1:80")};

expectSessionCreate();
expectHealthcheckStart(0);
EXPECT_CALL(event_logger_, logUnhealthy(_, _, _, true));
health_checker_->start();

expectHealthcheckStop(0);
// Resets are considered network failures and make host unhealthy also after 2nd event.
EXPECT_CALL(*this, onHostStatus(_, HealthTransition::ChangePending));
test_sessions_[0]->request_encoder_.stream_.resetStream(Http::StreamResetReason::RemoteReset);
expectHostHealthy(true);

// A new client is created because we close the connection
// when a stream reset occurs and connection reuse is disabled.
expectClientCreate(0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same comment here

expectHealthcheckStart(0);
test_sessions_[0]->interval_timer_->invokeCallback();

expectHealthcheckStop(0);
// Test host state haven't changed.
EXPECT_CALL(*this, onHostStatus(_, HealthTransition::Unchanged));
respondServiceStatus(0, grpc::health::v1::HealthCheckResponse::SERVING);
expectHostHealthy(true);
}

// Test UNKNOWN health status is considered unhealthy.
TEST_F(GrpcHealthCheckerImplTest, GrpcFailUnknown) {
setupHC();
Expand Down