Skip to content

Commit 6b5bd57

Browse files
author
oigolovanova
committed
feat grpc: read abs tp from the new header field
commit_hash:b7a9cf9862d6aca03992007efa9f5f7e117ee01e
1 parent 3037180 commit 6b5bd57

File tree

18 files changed

+434
-113
lines changed

18 files changed

+434
-113
lines changed

.mapping.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1148,6 +1148,7 @@
11481148
"core/include/userver/server/middlewares/cors.hpp":"taxi/uservices/userver/core/include/userver/server/middlewares/cors.hpp",
11491149
"core/include/userver/server/middlewares/headers_propagator.hpp":"taxi/uservices/userver/core/include/userver/server/middlewares/headers_propagator.hpp",
11501150
"core/include/userver/server/middlewares/http_middleware_base.hpp":"taxi/uservices/userver/core/include/userver/server/middlewares/http_middleware_base.hpp",
1151+
"core/include/userver/server/request/impl/absolute_deadline.hpp":"taxi/uservices/userver/core/include/userver/server/request/impl/absolute_deadline.hpp",
11511152
"core/include/userver/server/request/json_data.hpp":"taxi/uservices/userver/core/include/userver/server/request/json_data.hpp",
11521153
"core/include/userver/server/request/request_config.hpp":"taxi/uservices/userver/core/include/userver/server/request/request_config.hpp",
11531154
"core/include/userver/server/request/request_context.hpp":"taxi/uservices/userver/core/include/userver/server/request/request_context.hpp",
@@ -2027,6 +2028,7 @@
20272028
"core/src/server/net/listener_impl.hpp":"taxi/uservices/userver/core/src/server/net/listener_impl.hpp",
20282029
"core/src/server/net/stats.hpp":"taxi/uservices/userver/core/src/server/net/stats.hpp",
20292030
"core/src/server/pph_config.hpp":"taxi/uservices/userver/core/src/server/pph_config.hpp",
2031+
"core/src/server/request/impl/absolute_deadline.cpp":"taxi/uservices/userver/core/src/server/request/impl/absolute_deadline.cpp",
20302032
"core/src/server/request/internal_request_context.cpp":"taxi/uservices/userver/core/src/server/request/internal_request_context.cpp",
20312033
"core/src/server/request/internal_request_context.hpp":"taxi/uservices/userver/core/src/server/request/internal_request_context.hpp",
20322034
"core/src/server/request/json_data.cpp":"taxi/uservices/userver/core/src/server/request/json_data.cpp",
@@ -2287,6 +2289,7 @@
22872289
"grpc/functional_tests/basic_chaos/tests-grpcserver/test_server_smaller_parts.py":"taxi/uservices/userver/grpc/functional_tests/basic_chaos/tests-grpcserver/test_server_smaller_parts.py",
22882290
"grpc/functional_tests/basic_chaos/tests-nonchaos/conftest.py":"taxi/uservices/userver/grpc/functional_tests/basic_chaos/tests-nonchaos/conftest.py",
22892291
"grpc/functional_tests/basic_chaos/tests-nonchaos/test_basic.py":"taxi/uservices/userver/grpc/functional_tests/basic_chaos/tests-nonchaos/test_basic.py",
2292+
"grpc/functional_tests/basic_chaos/tests-nonchaos/test_deadline_absolute.py":"taxi/uservices/userver/grpc/functional_tests/basic_chaos/tests-nonchaos/test_deadline_absolute.py",
22902293
"grpc/functional_tests/basic_chaos/tests-nonchaos/test_tracing_metadata.py":"taxi/uservices/userver/grpc/functional_tests/basic_chaos/tests-nonchaos/test_tracing_metadata.py",
22912294
"grpc/functional_tests/basic_server/CMakeLists.txt":"taxi/uservices/userver/grpc/functional_tests/basic_server/CMakeLists.txt",
22922295
"grpc/functional_tests/basic_server/grpc_service.cpp":"taxi/uservices/userver/grpc/functional_tests/basic_server/grpc_service.cpp",
@@ -2662,6 +2665,8 @@
26622665
"grpc/src/ugrpc/server/middlewares/congestion_control/component.yaml":"taxi/uservices/userver/grpc/src/ugrpc/server/middlewares/congestion_control/component.yaml",
26632666
"grpc/src/ugrpc/server/middlewares/congestion_control/middleware.cpp":"taxi/uservices/userver/grpc/src/ugrpc/server/middlewares/congestion_control/middleware.cpp",
26642667
"grpc/src/ugrpc/server/middlewares/congestion_control/middleware.hpp":"taxi/uservices/userver/grpc/src/ugrpc/server/middlewares/congestion_control/middleware.hpp",
2668+
"grpc/src/ugrpc/server/middlewares/deadline_propagation/component.cpp":"taxi/uservices/userver/grpc/src/ugrpc/server/middlewares/deadline_propagation/component.cpp",
2669+
"grpc/src/ugrpc/server/middlewares/deadline_propagation/component.yaml":"taxi/uservices/userver/grpc/src/ugrpc/server/middlewares/deadline_propagation/component.yaml",
26652670
"grpc/src/ugrpc/server/middlewares/deadline_propagation/middleware.cpp":"taxi/uservices/userver/grpc/src/ugrpc/server/middlewares/deadline_propagation/middleware.cpp",
26662671
"grpc/src/ugrpc/server/middlewares/graceful_shutdown_headers/component.cpp":"taxi/uservices/userver/grpc/src/ugrpc/server/middlewares/graceful_shutdown_headers/component.cpp",
26672672
"grpc/src/ugrpc/server/middlewares/graceful_shutdown_headers/middleware.cpp":"taxi/uservices/userver/grpc/src/ugrpc/server/middlewares/graceful_shutdown_headers/middleware.cpp",
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#pragma once
2+
3+
/// @file userver/server/request/impl/absolute_deadline.hpp
4+
/// @brief Absolute deadline parsing and engine deadline construction for propagation.
5+
6+
#include <chrono>
7+
#include <optional>
8+
#include <string>
9+
10+
#include <userver/dynamic_config/fwd.hpp>
11+
#include <userver/engine/deadline.hpp>
12+
#include <userver/tracing/fwd.hpp>
13+
14+
USERVER_NAMESPACE_BEGIN
15+
16+
namespace server::request {
17+
18+
using TaskInheritedOriginalDeadline = std::chrono::time_point<std::chrono::system_clock, std::chrono::microseconds>;
19+
20+
namespace impl {
21+
22+
std::optional<TaskInheritedOriginalDeadline> ParseXRequestDeadlineString(const std::string& timestring);
23+
24+
std::optional<engine::Deadline> TryMakeDeadlinePreferringAbsoluteTimestamp(
25+
const std::optional<TaskInheritedOriginalDeadline>& absolute_original_deadline,
26+
bool deadline_propagation_prefer_timestamp,
27+
const std::optional<std::chrono::milliseconds>& client_deadline_duration,
28+
const dynamic_config::Snapshot& config,
29+
tracing::Span* span
30+
);
31+
32+
} // namespace impl
33+
34+
} // namespace server::request
35+
36+
USERVER_NAMESPACE_END

core/include/userver/server/request/task_inherited_data.hpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,17 @@
66
#include <atomic>
77
#include <chrono>
88
#include <optional>
9-
#include <string>
9+
#include <string_view>
1010

1111
#include <userver/engine/deadline.hpp>
1212
#include <userver/engine/task/inherited_variable.hpp>
13+
#include <userver/server/request/impl/absolute_deadline.hpp>
1314

1415
USERVER_NAMESPACE_BEGIN
1516

1617
/// Server request related types and functions
1718
namespace server::request {
1819

19-
/// Microsecond-precision system-clock instant (e.g. from `X-Request-Deadline`).
20-
using TaskInheritedOriginalDeadline = std::chrono::time_point<std::chrono::system_clock, std::chrono::microseconds>;
21-
2220
/// @brief Signals when an operation has detected deadline expiration.
2321
class DeadlineSignal final {
2422
public:

core/include/userver/tracing/span.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,8 @@ class Span final {
277277

278278
std::chrono::system_clock::time_point GetStartSystemTime() const;
279279

280+
std::chrono::steady_clock::time_point GetStartSteadyTime() const;
281+
280282
/// @cond
281283
// For internal use only.
282284
void AddTags(const logging::LogExtra&, utils::impl::InternalTag);

core/src/server/middlewares/deadline_propagation.cpp

Lines changed: 26 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <server/handlers/http_server_settings.hpp>
44
#include <server/request/internal_request_context.hpp>
55

6+
#include <userver/engine/deadline.hpp>
67
#include <userver/http/common_headers.hpp>
78
#include <userver/server/handlers/exceptions.hpp>
89
#include <userver/server/handlers/http_handler_base.hpp>
@@ -14,10 +15,6 @@
1415
#include <userver/utils/from_string.hpp>
1516
#include <userver/utils/overloaded.hpp>
1617

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>
2118
#include <dynamic_config/variables/USERVER_DEADLINE_PROPAGATION_ENABLED.hpp>
2219

2320
USERVER_NAMESPACE_BEGIN
@@ -64,53 +61,6 @@ std::optional<std::chrono::milliseconds> ParseTimeout(const http::HttpRequest& r
6461
return timeout;
6562
}
6663

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-
11464
void SetFormattedErrorResponse(http::HttpResponse& http_response, handlers::FormattedErrorData&& formatted_error_data) {
11565
http_response.SetData(std::move(formatted_error_data.external_body));
11666
if (formatted_error_data.content_type) {
@@ -204,48 +154,46 @@ void DeadlinePropagation::SetupInheritedDeadline(
204154
return;
205155
}
206156

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()) {
209163
inherited_data.original_deadline = original_deadline;
210164
}
211165

212-
std::optional<engine::Deadline> chosen_deadline;
213-
std::int64_t span_deadline_received_ms = 0;
214166
auto* span_opt = tracing::Span::CurrentSpanUnchecked();
215167
const auto timeout = ParseTimeout(request);
216168

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()) {
238180
return;
239181
}
240182
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());
242190
}
243191

244192
inherited_data.deadline = *chosen_deadline;
245193
dp_scope.need_log_response = config_snapshot[::dynamic_config::USERVER_LOG_REQUEST];
246194

247195
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());
249197
}
250198

251199
if (chosen_deadline->IsSurelyReachedApprox()) {
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
#include <userver/server/request/impl/absolute_deadline.hpp>
2+
3+
#include <string>
4+
5+
#include <userver/dynamic_config/snapshot.hpp>
6+
#include <userver/logging/log.hpp>
7+
#include <userver/tracing/span.hpp>
8+
#include <userver/utils/datetime.hpp>
9+
10+
#include <dynamic_config/variables/USERVER_DEADLINE_PROPAGATION_ABSOLUTE_TIMESTAMP_ENABLED.hpp>
11+
#include <dynamic_config/variables/USERVER_DEADLINE_PROPAGATION_CLOCK_SKEW_THRESHOLD_MS.hpp>
12+
13+
USERVER_NAMESPACE_BEGIN
14+
15+
namespace server::request::impl {
16+
17+
namespace {
18+
19+
bool IsClockSkewAcceptable(
20+
const TaskInheritedOriginalDeadline& absolute_tp,
21+
std::chrono::milliseconds deadline_duration,
22+
std::chrono::milliseconds threshold,
23+
tracing::Span* span
24+
) {
25+
if (threshold == std::chrono::milliseconds{0}) {
26+
return true;
27+
}
28+
29+
const auto request_start_system_time = span ? span->GetStartSystemTime() : utils::datetime::Now();
30+
const auto expected_timestamp =
31+
std::chrono::time_point_cast<std::chrono::microseconds>(request_start_system_time) + deadline_duration;
32+
33+
const auto skew = std::chrono::abs(absolute_tp - expected_timestamp);
34+
const auto skew_ms = std::chrono::duration_cast<std::chrono::milliseconds>(skew);
35+
36+
if (span != nullptr) {
37+
span->AddNonInheritableTag("dp_clock_skew_ms", skew_ms.count());
38+
}
39+
40+
if (skew_ms > threshold) {
41+
LOG_LIMITED_WARNING()
42+
<< "Clock skew detected: " << skew_ms << ", threshold: " << threshold
43+
<< ". Falling back to duration-based deadline propagation";
44+
return false;
45+
}
46+
47+
return true;
48+
}
49+
50+
} // namespace
51+
52+
std::optional<TaskInheritedOriginalDeadline> ParseXRequestDeadlineString(const std::string& timestring) {
53+
if (timestring.empty()) {
54+
return std::nullopt;
55+
}
56+
try {
57+
const auto timestamp = utils::datetime::UtcStringtime(timestring, utils::datetime::kTaximeterFormat);
58+
return std::chrono::time_point_cast<std::chrono::microseconds>(timestamp);
59+
} catch (const std::exception& exception) {
60+
LOG_LIMITED_WARNING() << "Can't parse X-Request-Deadline: " << exception.what();
61+
return std::nullopt;
62+
}
63+
}
64+
65+
std::optional<engine::Deadline> TryMakeDeadlinePreferringAbsoluteTimestamp(
66+
const std::optional<TaskInheritedOriginalDeadline>& absolute_original_deadline,
67+
const bool deadline_propagation_prefer_timestamp,
68+
const std::optional<std::chrono::milliseconds>& client_deadline_duration,
69+
const dynamic_config::Snapshot& config,
70+
tracing::Span* span
71+
) {
72+
if (!absolute_original_deadline.has_value() || !deadline_propagation_prefer_timestamp ||
73+
!config[::dynamic_config::USERVER_DEADLINE_PROPAGATION_ABSOLUTE_TIMESTAMP_ENABLED])
74+
{
75+
return std::nullopt;
76+
}
77+
78+
bool use_absolute = true;
79+
if (client_deadline_duration.has_value()) {
80+
use_absolute = IsClockSkewAcceptable(
81+
*absolute_original_deadline,
82+
*client_deadline_duration,
83+
config[::dynamic_config::USERVER_DEADLINE_PROPAGATION_CLOCK_SKEW_THRESHOLD_MS],
84+
span
85+
);
86+
}
87+
88+
if (use_absolute) {
89+
return engine::Deadline::FromTimePoint(*absolute_original_deadline);
90+
}
91+
return std::nullopt;
92+
}
93+
94+
} // namespace server::request::impl
95+
96+
USERVER_NAMESPACE_END

core/src/tracing/span.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,8 @@ void Span::AttachToCoroStack() { pimpl_->AttachToCoroStack(); }
434434

435435
std::chrono::system_clock::time_point Span::GetStartSystemTime() const { return pimpl_->start_system_time_; }
436436

437+
std::chrono::steady_clock::time_point Span::GetStartSteadyTime() const { return pimpl_->start_steady_time_; }
438+
437439
std::string_view Span::GetTraceId() const { return pimpl_->GetTraceId(); }
438440

439441
std::string_view Span::GetSpanId() const { return pimpl_->GetSpanId(); }

grpc/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ list(
4747
src/ugrpc/client/simple_client_component.yaml
4848
src/ugrpc/server/middlewares/access_log/component.yaml
4949
src/ugrpc/server/middlewares/congestion_control/component.yaml
50+
src/ugrpc/server/middlewares/deadline_propagation/component.yaml
5051
src/ugrpc/server/middlewares/headers_propagator/component.yaml
5152
src/ugrpc/server/middlewares/log/component.yaml
5253
src/ugrpc/server/server_component.yaml

grpc/functional_tests/basic_chaos/main.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <userver/clients/http/component_list.hpp>
55
#include <userver/components/minimal_server_component_list.hpp>
66
#include <userver/congestion_control/component.hpp>
7+
#include <userver/dynamic_config/updater/component_list.hpp>
78
#include <userver/server/handlers/tests_control.hpp>
89
#include <userver/testsuite/testsuite_support.hpp>
910
#include <userver/ugrpc/client/client_factory_component.hpp>
@@ -18,6 +19,7 @@
1819
int main(int argc, char* argv[]) {
1920
const auto component_list =
2021
components::MinimalServerComponentList()
22+
.AppendComponentList(USERVER_NAMESPACE::dynamic_config::updater::ComponentList())
2123
.Append<components::TestsuiteSupport>()
2224
.AppendComponentList(ugrpc::server::DefaultComponentList())
2325
.Append<ugrpc::server::middlewares::access_log::Component>()

0 commit comments

Comments
 (0)