-
Notifications
You must be signed in to change notification settings - Fork 5.5k
Health checks: Add retriable http health check statuses. #17948
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 12 commits
1565ef0
f631c7f
981b5f2
edbe062
9646866
3f7db44
f4295fb
ab37ada
239f73a
4a27d0a
0366c98
1176ebc
66d4129
c7e875e
889adec
70714be
431ec59
6a5ebf4
d8a8f30
94d04d2
fdc5eae
565e42e
e3e5aae
eefbf9f
2c70a2a
2cada4d
52bcc5f
37c41e8
6d80517
6a5269e
5599a92
974191a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -76,7 +76,8 @@ class HealthCheckerImplBase : public HealthChecker, | |
| class ActiveHealthCheckSession : public Event::DeferredDeletable { | ||
| public: | ||
| ~ActiveHealthCheckSession() override; | ||
| HealthTransition setUnhealthy(envoy::data::core::v3::HealthCheckFailureType type); | ||
| HealthTransition setUnhealthy(envoy::data::core::v3::HealthCheckFailureType type, | ||
| bool retriable); | ||
|
Comment on lines
+79
to
+80
Member
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. Compared to adding a boolean parameter, can we add a new HealthCheckFailure value
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. We could. That will also affect the
Member
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. Interesting point. I think the boolean expresses the API nicely because the failure type is still ACTIVE, it just happens to be retriable. |
||
| void onDeferredDeleteBase(); | ||
| void start() { onInitialInterval(); } | ||
|
|
||
|
|
@@ -85,7 +86,7 @@ class HealthCheckerImplBase : public HealthChecker, | |
|
|
||
| void handleSuccess(bool degraded = false); | ||
| void handleDegraded(); | ||
| void handleFailure(envoy::data::core::v3::HealthCheckFailureType type); | ||
| void handleFailure(envoy::data::core::v3::HealthCheckFailureType type, bool retriable = false); | ||
|
|
||
| HostSharedPtr host_; | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -138,6 +138,7 @@ HttpHealthCheckerImpl::HttpHealthCheckerImpl(const Cluster& cluster, | |
| Router::HeaderParser::configure(config.http_health_check().request_headers_to_add(), | ||
| config.http_health_check().request_headers_to_remove())), | ||
| http_status_checker_(config.http_health_check().expected_statuses(), | ||
| config.http_health_check().retriable_statuses(), | ||
| static_cast<uint64_t>(Http::Code::OK)), | ||
| codec_client_type_(codecClientType(config.http_health_check().codec_client_type())), | ||
| random_generator_(random) { | ||
|
|
@@ -148,6 +149,7 @@ HttpHealthCheckerImpl::HttpHealthCheckerImpl(const Cluster& cluster, | |
|
|
||
| HttpHealthCheckerImpl::HttpStatusChecker::HttpStatusChecker( | ||
| const Protobuf::RepeatedPtrField<envoy::type::v3::Int64Range>& expected_statuses, | ||
| const Protobuf::RepeatedPtrField<envoy::type::v3::Int64Range>& retriable_statuses, | ||
| uint64_t default_expected_status) { | ||
| for (const auto& status_range : expected_statuses) { | ||
| const auto start = status_range.start(); | ||
|
|
@@ -169,16 +171,53 @@ HttpHealthCheckerImpl::HttpStatusChecker::HttpStatusChecker( | |
| fmt::format("Invalid http status range: expecting end <= 600, but found end={}", end)); | ||
| } | ||
|
|
||
| ranges_.emplace_back(std::make_pair(static_cast<uint64_t>(start), static_cast<uint64_t>(end))); | ||
| expected_ranges_.emplace_back( | ||
| std::make_pair(static_cast<uint64_t>(start), static_cast<uint64_t>(end))); | ||
| } | ||
|
|
||
| if (ranges_.empty()) { | ||
| ranges_.emplace_back(std::make_pair(default_expected_status, default_expected_status + 1)); | ||
| if (expected_ranges_.empty()) { | ||
| expected_ranges_.emplace_back( | ||
| std::make_pair(default_expected_status, default_expected_status + 1)); | ||
| } | ||
|
|
||
| for (const auto& status_range : retriable_statuses) { | ||
| const auto start = status_range.start(); | ||
| const auto end = status_range.end(); | ||
|
|
||
| if (start >= end) { | ||
| throw EnvoyException(fmt::format("Invalid http retriable status range: expecting start < " | ||
| "end, but found start={} and end={}", | ||
| start, end)); | ||
| } | ||
|
|
||
| if (start < 100) { | ||
| throw EnvoyException(fmt::format( | ||
| "Invalid http retriable status range: expecting start >= 100, but found start={}", | ||
| start)); | ||
| } | ||
|
|
||
| if (end > 600) { | ||
| throw EnvoyException(fmt::format( | ||
| "Invalid http retriable status range: expecting end <= 600, but found end={}", end)); | ||
| } | ||
|
|
||
| retriable_ranges_.emplace_back( | ||
|
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. Consider adding a range intersection verification against the
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. Left this for now since I'm initially leaning towards allowing overlap for simplicity. This is now reflected in the API docs.
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. SGTM
Member
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. Can we wrapper this redundant range-checking codes to a validate func or some thing? |
||
| std::make_pair(static_cast<uint64_t>(start), static_cast<uint64_t>(end))); | ||
| } | ||
| } | ||
|
|
||
| bool HttpHealthCheckerImpl::HttpStatusChecker::inRange(uint64_t http_status) const { | ||
| for (const auto& range : ranges_) { | ||
| bool HttpHealthCheckerImpl::HttpStatusChecker::inExpectedRange(uint64_t http_status) const { | ||
| for (const auto& range : expected_ranges_) { | ||
| if (http_status >= range.first && http_status < range.second) { | ||
| return true; | ||
| } | ||
| } | ||
|
|
||
| return false; | ||
| } | ||
|
|
||
| bool HttpHealthCheckerImpl::HttpStatusChecker::inRetriableRange(uint64_t http_status) const { | ||
|
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. nit: avoid code duplication by refactoring
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. I agree with this but I think the two ranges fields should remain private and the callers should still use lightly wrapped functions inExpectedRange and inRetriablyRange. The inner private function would have the common factored out code. What do you think?
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. This is in response to c7e875e
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. Yes, that is better, thanks. Will update |
||
| for (const auto& range : retriable_ranges_) { | ||
| if (http_status >= range.first && http_status < range.second) { | ||
| return true; | ||
| } | ||
|
|
@@ -331,7 +370,7 @@ HttpHealthCheckerImpl::HttpActiveHealthCheckSession::healthCheckResult() { | |
| ENVOY_CONN_LOG(debug, "hc response={} health_flags={}", *client_, response_code, | ||
| HostUtility::healthFlagsToString(*host_)); | ||
|
|
||
| if (!parent_.http_status_checker_.inRange(response_code)) { | ||
| if (!parent_.http_status_checker_.inExpectedRange(response_code)) { | ||
| // If the HTTP response code would indicate failure AND the immediate health check | ||
| // failure header is set, exclude the host from LB. | ||
| // TODO(mattklein123): We could consider doing this check for any HTTP response code, but this | ||
|
|
@@ -341,7 +380,12 @@ HttpHealthCheckerImpl::HttpActiveHealthCheckSession::healthCheckResult() { | |
| if (response_headers_->EnvoyImmediateHealthCheckFail() != nullptr) { | ||
| host_->healthFlagSet(Host::HealthFlag::EXCLUDED_VIA_IMMEDIATE_HC_FAIL); | ||
| } | ||
| return HealthCheckResult::Failed; | ||
|
|
||
| if (parent_.http_status_checker_.inRetriableRange(response_code)) { | ||
| return HealthCheckResult::Retriable; | ||
| } else { | ||
| return HealthCheckResult::Failed; | ||
| } | ||
| } | ||
|
|
||
| const auto degraded = response_headers_->EnvoyDegraded() != nullptr; | ||
|
|
@@ -374,7 +418,10 @@ void HttpHealthCheckerImpl::HttpActiveHealthCheckSession::onResponseComplete() { | |
| handleSuccess(true); | ||
| break; | ||
| case HealthCheckResult::Failed: | ||
| handleFailure(envoy::data::core::v3::ACTIVE); | ||
| handleFailure(envoy::data::core::v3::ACTIVE, false); | ||
| break; | ||
| case HealthCheckResult::Retriable: | ||
| handleFailure(envoy::data::core::v3::ACTIVE, true); | ||
|
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. Might want to comment the boolean parameter for extra clarity. Something like |
||
| break; | ||
| } | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.