-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
router: set correct timeout for egress->ingress envoys #8051
Changes from 7 commits
5c5a706
2b3080d
b36858a
99cd2cd
be4d596
de1fdf2
b0ea85a
cbb9594
90695da
8432d62
967acfd
1450fc9
cc6f485
8992d02
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 |
---|---|---|
|
@@ -63,4 +63,10 @@ message Router { | |
"x-envoy-retry-on" | ||
] | ||
}]; | ||
|
||
// If set to true, envoy first will check if `x-envoy-expected-timeout-ms` header is present | ||
// and use it's value as timeout to upstream cluster. If header is not present or | ||
// `respect_expected_rq_timeout` is set to false, envoy will derive timeout value from | ||
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 you 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: s/envoy/Envoy/g |
||
// `x-envoy-upstream-rq-timeout-ms` header. | ||
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 dont think this is completely correct, as there might not be a rq-timeout header in which case the route specified timeout is used. Might be better to avoid listing what the behavior is without this flag to help ensure that this comment doesn't have to be updated whenever the timeout decision logic changes |
||
bool respect_expected_rq_timeout = 6; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -121,7 +121,8 @@ bool FilterUtility::shouldShadow(const ShadowPolicy& policy, Runtime::Loader& ru | |
FilterUtility::TimeoutData | ||
FilterUtility::finalTimeout(const RouteEntry& route, Http::HeaderMap& request_headers, | ||
bool insert_envoy_expected_request_timeout_ms, bool grpc_request, | ||
bool per_try_timeout_hedging_enabled) { | ||
bool per_try_timeout_hedging_enabled, | ||
bool respect_expected_rq_timeout) { | ||
// See if there is a user supplied timeout in a request header. If there is we take that. | ||
// Otherwise if the request is gRPC and a maximum gRPC timeout is configured we use the timeout | ||
// in the gRPC headers (or infinity when gRPC headers have no timeout), but cap that timeout to | ||
|
@@ -151,13 +152,39 @@ FilterUtility::finalTimeout(const RouteEntry& route, Http::HeaderMap& request_he | |
} | ||
timeout.per_try_timeout_ = route.retryPolicy().perTryTimeout(); | ||
|
||
Http::HeaderEntry* header_timeout_entry = request_headers.EnvoyUpstreamRequestTimeoutMs(); | ||
uint64_t header_timeout; | ||
if (header_timeout_entry) { | ||
if (absl::SimpleAtoi(header_timeout_entry->value().getStringView(), &header_timeout)) { | ||
timeout.global_timeout_ = std::chrono::milliseconds(header_timeout); | ||
|
||
if (respect_expected_rq_timeout) { | ||
htuch marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// Check if there is timeout set by egress envoy. | ||
// If present, use that value as route timeout and don't override | ||
// `x-envoy-expected-rq-timeout-ms` header. At this point `x-envoy-upstream-rq-timeout-ms` | ||
// header should have been sanitized by egress envoy. | ||
Http::HeaderEntry* header_expected_timeout_entry = | ||
request_headers.EnvoyExpectedRequestTimeoutMs(); | ||
if (header_expected_timeout_entry) { | ||
// This will prevent from overriding `x-envoy-expected-rq-timeout-ms` header. | ||
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. do we need this? won't this be set based on the global_timeout_ later on which should match the value we're extracting from the expected-rq-timeout-ms header? 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. @snowp this was protection against this code path:
We do indeed derive timeout and put it into a separate data structure (with global timeout), so there is not a big gain from setting 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. changed my mind, there is a gain, so that we use same value in timeout.global_timeout (derived from 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. Hmm, I think we want the expected header to reflect the timeout used by the router, which is affected by more than just those two headers. If you look further down in that function you'll see that we'll use the per try timeout instead of the global timeout if it's set. It seems like we want the expected timeout header to always reflect the timeout enforced by the router for the outgoing request, and just use the incoming expected timeout header to infer the global timeout. Does that make sense? 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. @snowp it does, thanks for clarification 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. will adjust the test as well |
||
insert_envoy_expected_request_timeout_ms = false; | ||
if (absl::SimpleAtoi(header_expected_timeout_entry->value().getStringView(), | ||
&header_timeout)) { | ||
timeout.global_timeout_ = std::chrono::milliseconds(header_timeout); | ||
} | ||
} else { | ||
Http::HeaderEntry* header_timeout_entry = request_headers.EnvoyUpstreamRequestTimeoutMs(); | ||
if (header_timeout_entry) { | ||
if (absl::SimpleAtoi(header_timeout_entry->value().getStringView(), &header_timeout)) { | ||
timeout.global_timeout_ = std::chrono::milliseconds(header_timeout); | ||
} | ||
request_headers.removeEnvoyUpstreamRequestTimeoutMs(); | ||
} | ||
} | ||
} else { | ||
Http::HeaderEntry* header_timeout_entry = request_headers.EnvoyUpstreamRequestTimeoutMs(); | ||
if (header_timeout_entry) { | ||
if (absl::SimpleAtoi(header_timeout_entry->value().getStringView(), &header_timeout)) { | ||
timeout.global_timeout_ = std::chrono::milliseconds(header_timeout); | ||
} | ||
request_headers.removeEnvoyUpstreamRequestTimeoutMs(); | ||
} | ||
request_headers.removeEnvoyUpstreamRequestTimeoutMs(); | ||
} | ||
|
||
// See if there is a per try/retry timeout. If it's >= global we just ignore it. | ||
|
@@ -484,7 +511,8 @@ Http::FilterHeadersStatus Filter::decodeHeaders(Http::HeaderMap& headers, bool e | |
hedging_params_ = FilterUtility::finalHedgingParams(*route_entry_, headers); | ||
|
||
timeout_ = FilterUtility::finalTimeout(*route_entry_, headers, !config_.suppress_envoy_headers_, | ||
grpc_request_, hedging_params_.hedge_on_per_try_timeout_); | ||
grpc_request_, hedging_params_.hedge_on_per_try_timeout_, | ||
config_.respect_expected_rq_timeout_); | ||
|
||
// If this header is set with any value, use an alternate response code on timeout | ||
if (headers.EnvoyUpstreamRequestTimeoutAltResponse()) { | ||
|
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.
nit: "will first check if the `x-envoy"
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.
Also use
*x-envoy-expected-timeout-ms*
formatting for headers.