Skip to content

Commit

Permalink
health check: close conn after timeout/stream rst when grpc hc has co…
Browse files Browse the repository at this point in the history
…nn reuse disabled (envoyproxy#11325)

Close connection after timeout/stream reset when grpc health checker has connection reuse disabled.

Signed-off-by: Joey Muia <joseph.b.muia@gmail.com>
Signed-off-by: Auni Ahsan <auni@google.com>
  • Loading branch information
jmuia authored and auni53 committed Jun 4, 2020
1 parent d3ee8ba commit e3d95a3
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 1 deletion.
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) {
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);
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

0 comments on commit e3d95a3

Please sign in to comment.