-
Notifications
You must be signed in to change notification settings - Fork 5.5k
HTTP health checker: handle GOAWAY from HTTP2 upstreams #13599
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 8 commits
ce00ea3
9f83533
736d0ca
f3e9da2
b76c46e
01fa365
cd06c28
f899f0a
8f21af4
c23a9a5
447d07c
04458ab
0d57547
15d4dcd
00503eb
bbd6e08
bb0cc29
2b00126
2352719
ed7a0f1
38cc1bf
0bd20e6
38c4fb8
b4496a9
6dd4400
41a330b
bbb5b8e
8cd1560
ec669f2
455034a
e75b30a
df8f734
56efbce
2b0d930
9e339ee
0345dba
06652ed
322e564
deb3893
3ff4d9f
bcb7346
f74ed68
1c287c1
49e689d
a7cfa59
d15bbf3
31c0641
5e8b981
6a3ad8c
eacd1f4
64cc217
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -256,11 +256,14 @@ void HttpHealthCheckerImpl::HttpActiveHealthCheckSession::onInterval() { | |
| parent_.transportSocketMatchMetadata().get()); | ||
| client_.reset(parent_.createCodecClient(conn)); | ||
| client_->addConnectionCallbacks(connection_callback_impl_); | ||
| client_->setCodecConnectionCallbacks(http_connection_callback_impl_); | ||
| expect_reset_ = false; | ||
| received_no_error_goaway_ = false; | ||
| } | ||
|
|
||
| Http::RequestEncoder* request_encoder = &client_->newStream(*this); | ||
| request_encoder->getStream().addCallbacks(*this); | ||
| request_in_flight_ = true; | ||
|
|
||
| const auto request_headers = Http::createHeaderMap<Http::RequestHeaderMapImpl>( | ||
| {{Http::Headers::get().Method, "GET"}, | ||
|
|
@@ -279,15 +282,50 @@ void HttpHealthCheckerImpl::HttpActiveHealthCheckSession::onInterval() { | |
|
|
||
| void HttpHealthCheckerImpl::HttpActiveHealthCheckSession::onResetStream(Http::StreamResetReason, | ||
| absl::string_view) { | ||
| request_in_flight_ = false; | ||
| ENVOY_CONN_LOG(debug, "connection/stream error health_flags={}", *client_, | ||
| HostUtility::healthFlagsToString(*host_)); | ||
| if (client_ && received_no_error_goaway_) { | ||
| client_->close(); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @alyssawilk this is the one place it might be weird to just use a
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll push the commit, we can always revert it
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah, closing if we can't reuse and the stream is reset seems fine, and it's behind the guard so even if someone gets surprised they can always revert the behavior
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. some of this behavior change is not guarded. It looks like the same case came up when implementing GOAWAY handling in gRPC. There is a slight behavior change if you have connection reuse disabled, and get a reset stream. Previously the connection would be reused! which seems wrong, but is an unguarded behavior change. Reference PR: #11325 |
||
| } | ||
|
|
||
| if (expect_reset_) { | ||
| return; | ||
| } | ||
|
|
||
| ENVOY_CONN_LOG(debug, "connection/stream error health_flags={}", *client_, | ||
| HostUtility::healthFlagsToString(*host_)); | ||
| handleFailure(envoy::data::core::v3::NETWORK); | ||
| } | ||
|
|
||
| void HttpHealthCheckerImpl::HttpActiveHealthCheckSession::onGoAway( | ||
| Http::GoAwayErrorCode error_code) { | ||
| ENVOY_CONN_LOG(debug, "connection going away health_flags={}", *client_, | ||
| HostUtility::healthFlagsToString(*host_)); | ||
|
|
||
| // If GOAWAY handling is explicitly disabled via runtime, go back to the old | ||
| // behavior of ignoring GOAWAY completely. | ||
| if (parent_.runtime_.snapshot().featureEnabled("health_check.disable_goaway_handling", 0UL)) { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @alyssawilk it turned out to be simple to go back to the old behavior. Let me know if I got the defaults the right direction, not sure if you wanted to make this opt-in or opt-out (it's currently opt-out).
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. opt-out is fine, but can you please check https://github.com/envoyproxy/envoy/blob/master/CONTRIBUTING.md#runtime-guarding |
||
| return; | ||
| } | ||
|
|
||
| if (request_in_flight_ && error_code == Http::GoAwayErrorCode::NoError) { | ||
| // The server is starting a graceful shutdown. Allow the in flight request | ||
| // to finish without treating this as a health check error, and then | ||
| // reconnect. | ||
| received_no_error_goaway_ = true; | ||
| return; | ||
| } | ||
|
|
||
| if (request_in_flight_) { | ||
| // Record this as a failed health check. | ||
| handleFailure(envoy::data::core::v3::NETWORK); | ||
| } | ||
|
|
||
| if (client_) { | ||
| expect_reset_ = true; | ||
|
mpuncel marked this conversation as resolved.
|
||
| client_->close(); | ||
| } | ||
| } | ||
|
|
||
| HttpHealthCheckerImpl::HttpActiveHealthCheckSession::HealthCheckResult | ||
| HttpHealthCheckerImpl::HttpActiveHealthCheckSession::healthCheckResult() { | ||
| uint64_t response_code = Http::Utility::getResponseStatus(*response_headers_); | ||
|
|
@@ -318,6 +356,8 @@ HttpHealthCheckerImpl::HttpActiveHealthCheckSession::healthCheckResult() { | |
| } | ||
|
|
||
| void HttpHealthCheckerImpl::HttpActiveHealthCheckSession::onResponseComplete() { | ||
| request_in_flight_ = false; | ||
|
|
||
| switch (healthCheckResult()) { | ||
| case HealthCheckResult::Succeeded: | ||
| handleSuccess(false); | ||
|
|
@@ -345,7 +385,7 @@ bool HttpHealthCheckerImpl::HttpActiveHealthCheckSession::shouldClose() const { | |
| return false; | ||
| } | ||
|
|
||
| if (!parent_.reuse_connection_) { | ||
| if (!parent_.reuse_connection_ || received_no_error_goaway_) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Curious, could we just set parent_.reuse_connection_ false when get the goaway, and let all the rest of the code proceed as usual? I assume if we're not reusing the connection it would close on stream reset or stream complete.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i think we need both because otherwise we wouldn't know what to reset
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe this is what you meant: one thing I could do is name this variable to |
||
| return true; | ||
| } | ||
|
|
||
|
|
@@ -375,6 +415,7 @@ bool HttpHealthCheckerImpl::HttpActiveHealthCheckSession::shouldClose() const { | |
| } | ||
|
|
||
| void HttpHealthCheckerImpl::HttpActiveHealthCheckSession::onTimeout() { | ||
| request_in_flight_ = false; | ||
| if (client_) { | ||
| host_->setActiveHealthFailureType(Host::ActiveHealthFailureType::TIMEOUT); | ||
| ENVOY_CONN_LOG(debug, "connection/stream timeout health_flags={}", *client_, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please call out the runtime guard here