|
3 | 3 | #include <server/handlers/http_server_settings.hpp> |
4 | 4 | #include <server/request/internal_request_context.hpp> |
5 | 5 |
|
| 6 | +#include <userver/engine/deadline.hpp> |
6 | 7 | #include <userver/http/common_headers.hpp> |
7 | 8 | #include <userver/server/handlers/exceptions.hpp> |
8 | 9 | #include <userver/server/handlers/http_handler_base.hpp> |
|
14 | 15 | #include <userver/utils/from_string.hpp> |
15 | 16 | #include <userver/utils/overloaded.hpp> |
16 | 17 |
|
17 | | -#include <userver/utils/datetime.hpp> |
18 | | - |
19 | | -#include <dynamic_config/variables/USERVER_DEADLINE_PROPAGATION_ABSOLUTE_TIMESTAMP_ENABLED.hpp> |
20 | | -#include <dynamic_config/variables/USERVER_DEADLINE_PROPAGATION_CLOCK_SKEW_THRESHOLD_MS.hpp> |
21 | 18 | #include <dynamic_config/variables/USERVER_DEADLINE_PROPAGATION_ENABLED.hpp> |
22 | 19 |
|
23 | 20 | USERVER_NAMESPACE_BEGIN |
@@ -64,53 +61,6 @@ std::optional<std::chrono::milliseconds> ParseTimeout(const http::HttpRequest& r |
64 | 61 | return timeout; |
65 | 62 | } |
66 | 63 |
|
67 | | -std::optional<request::TaskInheritedOriginalDeadline> ParseAbsoluteDeadline(const http::HttpRequest& request) { |
68 | | - const auto& header_str = request.GetHeader(USERVER_NAMESPACE::http::headers::kXRequestDeadline); |
69 | | - if (header_str.empty()) { |
70 | | - return std::nullopt; |
71 | | - } |
72 | | - |
73 | | - LOG_DEBUG() << "Got X-Request-Deadline: " << header_str; |
74 | | - try { |
75 | | - const auto timestamp = utils::datetime::UtcStringtime(header_str, utils::datetime::kTaximeterFormat); |
76 | | - return std::chrono::time_point_cast<std::chrono::microseconds>(timestamp); |
77 | | - } catch (const std::exception& exception) { |
78 | | - LOG_LIMITED_WARNING() << "Can't parse X-Request-Deadline from '" << header_str << "': " << exception.what(); |
79 | | - return std::nullopt; |
80 | | - } |
81 | | -} |
82 | | - |
83 | | -/// Returns true if clock skew is within the threshold (absolute deadline is trustworthy). |
84 | | -bool IsClockSkewAcceptable( |
85 | | - const request::TaskInheritedOriginalDeadline& absolute_tp, |
86 | | - std::chrono::milliseconds duration_timeout, |
87 | | - std::chrono::milliseconds threshold, |
88 | | - tracing::Span* span |
89 | | -) { |
90 | | - if (threshold == std::chrono::milliseconds{0}) { |
91 | | - return true; // Check disabled |
92 | | - } |
93 | | - |
94 | | - const auto expected_timestamp = |
95 | | - std::chrono::time_point_cast<std::chrono::microseconds>(utils::datetime::Now()) + duration_timeout; |
96 | | - |
97 | | - const auto skew = std::chrono::abs(absolute_tp - expected_timestamp); |
98 | | - const auto skew_ms = std::chrono::duration_cast<std::chrono::milliseconds>(skew); |
99 | | - |
100 | | - if (span) { |
101 | | - span->AddNonInheritableTag("dp_clock_skew_ms", skew_ms.count()); |
102 | | - } |
103 | | - |
104 | | - if (skew_ms > threshold) { |
105 | | - LOG_LIMITED_WARNING() |
106 | | - << "Clock skew detected: " << skew_ms << ", threshold: " << threshold |
107 | | - << ". Falling back to duration-based deadline propagation"; |
108 | | - return false; |
109 | | - } |
110 | | - |
111 | | - return true; |
112 | | -} |
113 | | - |
114 | 64 | void SetFormattedErrorResponse(http::HttpResponse& http_response, handlers::FormattedErrorData&& formatted_error_data) { |
115 | 65 | http_response.SetData(std::move(formatted_error_data.external_body)); |
116 | 66 | if (formatted_error_data.content_type) { |
@@ -204,48 +154,46 @@ void DeadlinePropagation::SetupInheritedDeadline( |
204 | 154 | return; |
205 | 155 | } |
206 | 156 |
|
207 | | - const auto original_deadline = ParseAbsoluteDeadline(request); |
208 | | - if (original_deadline) { |
| 157 | + const auto& header_str = request.GetHeader(USERVER_NAMESPACE::http::headers::kXRequestDeadline); |
| 158 | + if (!header_str.empty()) { |
| 159 | + LOG_DEBUG() << "Got X-Request-Deadline: " << header_str; |
| 160 | + } |
| 161 | + const auto original_deadline = request::impl::ParseXRequestDeadlineString(header_str); |
| 162 | + if (original_deadline.has_value()) { |
209 | 163 | inherited_data.original_deadline = original_deadline; |
210 | 164 | } |
211 | 165 |
|
212 | | - std::optional<engine::Deadline> chosen_deadline; |
213 | | - std::int64_t span_deadline_received_ms = 0; |
214 | 166 | auto* span_opt = tracing::Span::CurrentSpanUnchecked(); |
215 | 167 | const auto timeout = ParseTimeout(request); |
216 | 168 |
|
217 | | - if (original_deadline.has_value() && deadline_propagation_prefer_timestamp_ && |
218 | | - config_snapshot[::dynamic_config::USERVER_DEADLINE_PROPAGATION_ABSOLUTE_TIMESTAMP_ENABLED]) |
219 | | - { |
220 | | - bool use_absolute = true; |
221 | | - if (timeout.has_value()) { |
222 | | - const auto& |
223 | | - threshold = config_snapshot[::dynamic_config::USERVER_DEADLINE_PROPAGATION_CLOCK_SKEW_THRESHOLD_MS]; |
224 | | - use_absolute = IsClockSkewAcceptable(*original_deadline, *timeout, threshold, span_opt); |
225 | | - } |
226 | | - |
227 | | - if (use_absolute) { |
228 | | - chosen_deadline = engine::Deadline::FromTimePoint(*original_deadline); |
229 | | - |
230 | | - const auto now_sys_micro = std::chrono::time_point_cast<std::chrono::microseconds>(utils::datetime::Now()); |
231 | | - span_deadline_received_ms = |
232 | | - std::chrono::duration_cast<std::chrono::milliseconds>(*original_deadline - now_sys_micro).count(); |
233 | | - } |
234 | | - } |
235 | | - |
236 | | - if (!chosen_deadline) { |
237 | | - if (!timeout) { |
| 169 | + std::optional<engine::Deadline> chosen_deadline = request::impl::TryMakeDeadlinePreferringAbsoluteTimestamp( |
| 170 | + original_deadline, |
| 171 | + deadline_propagation_prefer_timestamp_, |
| 172 | + timeout, |
| 173 | + config_snapshot, |
| 174 | + span_opt |
| 175 | + ); |
| 176 | + |
| 177 | + std::chrono::milliseconds span_deadline_received{0}; |
| 178 | + if (!chosen_deadline.has_value()) { |
| 179 | + if (!timeout.has_value()) { |
238 | 180 | return; |
239 | 181 | } |
240 | 182 | chosen_deadline = engine::Deadline::FromTimePoint(request.GetStartTime() + *timeout); |
241 | | - span_deadline_received_ms = timeout->count(); |
| 183 | + span_deadline_received = *timeout; |
| 184 | + } else { |
| 185 | + span_deadline_received = |
| 186 | + *chosen_deadline == engine::Deadline::Passed() |
| 187 | + ? std::chrono::milliseconds{0} |
| 188 | + : std::chrono::duration_cast< |
| 189 | + std::chrono::milliseconds>(chosen_deadline->GetTimePoint() - request.GetStartTime()); |
242 | 190 | } |
243 | 191 |
|
244 | 192 | inherited_data.deadline = *chosen_deadline; |
245 | 193 | dp_scope.need_log_response = config_snapshot[::dynamic_config::USERVER_LOG_REQUEST]; |
246 | 194 |
|
247 | 195 | if (span_opt) { |
248 | | - span_opt->AddNonInheritableTag("deadline_received_ms", span_deadline_received_ms); |
| 196 | + span_opt->AddNonInheritableTag("deadline_received_ms", span_deadline_received.count()); |
249 | 197 | } |
250 | 198 |
|
251 | 199 | if (chosen_deadline->IsSurelyReachedApprox()) { |
|
0 commit comments