userver: userver/storages/redis/hedged_request.hpp Source File
Loading...
Searching...
No Matches
hedged_request.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/storages/redis/hedged_request.hpp
4/// @brief
5/// Classes and functions for performing hedged requests.
6///
7/// Use MakeHedgedRedisRequest method to perform hedged redis request.
8///
9/// Example(Sync):
10/// auto result =
11/// ::redis::MakeHedgedRedisRequest<storages::redis::RequestHGet>(
12/// redis_client_shared_ptr,
13/// &storages::redis::Client::Hget,
14/// redis_cc, hedging_settings,
15/// key, field);
16/// Example(Async):
17/// auto future =
18/// ::redis::MakeHedgedRedisRequestAsync<storages::redis::RequestHGet>(
19/// redis_client_shared_ptr,
20/// &storages::redis::Client::Hget,
21/// redis_cc, hedging_settings,
22/// key, field);
23/// auto result = future.Get();
24///
25
26#include <optional>
27
28#include <userver/storages/redis/client.hpp>
29#include <userver/storages/redis/command_control.hpp>
30#include <userver/utils/hedged_request.hpp>
31
32USERVER_NAMESPACE_BEGIN
33
34namespace redis {
35namespace impl {
36
37template <typename RedisRequestType>
38struct RedisRequestStrategy {
39 public:
40 using RequestType = RedisRequestType;
41 using ReplyType = RequestType::Reply;
42 using GenF = std::function<std::optional<RequestType>(int)>;
43
44 explicit RedisRequestStrategy(GenF gen_callback)
45 : gen_callback_(std::move(gen_callback)) {}
46
47 RedisRequestStrategy(RedisRequestStrategy&& other) noexcept = default;
48
49 /// @{
50 /// Methods needed by HedgingStrategy
51 std::optional<RequestType> Create(size_t try_count) {
52 return gen_callback_(try_count);
53 }
54 std::optional<std::chrono::milliseconds> ProcessReply(RequestType&& request) {
55 reply_ = std::move(request).Get();
56 return std::nullopt;
57 }
58 std::optional<ReplyType> ExtractReply() { return std::move(reply_); }
59 void Finish(RequestType&&) {}
60 /// @}
61
62 private:
63 GenF gen_callback_;
64 std::optional<ReplyType> reply_;
65};
66
67} // namespace impl
68
69template <typename RedisRequestType>
70using HedgedRedisRequest = utils::hedging::HedgedRequestFuture<
71 impl::RedisRequestStrategy<RedisRequestType>>;
72
73template <typename RedisRequestType, typename... Args,
74 typename M = RedisRequestType (storages::redis::Client::*)(
75 Args..., const redis::CommandControl&)>
78 const redis::CommandControl& cc,
80 auto gen_request =
81 [redis, method, cc{std::move(cc)},
82 args_tuple{std::tuple(std::move(args)...)}](
83 int try_count) mutable -> std::optional<RedisRequestType> {
84 cc.retry_counter = try_count;
85 cc.max_retries = 1; ///< We do retries ourselves
86
87 return std::apply(
88 [redis, method, cc](auto&&... args) {
89 return (redis.get()->*method)(args..., cc);
90 },
91 args_tuple);
92 };
93 return utils::hedging::HedgeRequestAsync(
94 impl::RedisRequestStrategy<RedisRequestType>(std::move(gen_request)),
95 hedging_settings);
96}
97
98template <typename RedisRequestType>
99using HedgedRedisRequest = utils::hedging::HedgedRequestFuture<
100 impl::RedisRequestStrategy<RedisRequestType>>;
101
102template <typename RedisRequestType, typename... Args,
103 typename M = RedisRequestType (storages::redis::Client::*)(
104 Args..., const redis::CommandControl&)>
105RedisRequestType MakeHedgedRedisRequest(
106 std::shared_ptr<storages::redis::Client> redis, M method,
107 const redis::CommandControl& cc,
108 utils::hedging::HedgingSettings hedging_settings, Args... args) {
109 auto gen_request =
110 [redis, method, cc{std::move(cc)},
111 args_tuple{std::tuple(std::move(args)...)}](
112 int try_count) mutable -> std::optional<RedisRequestType> {
113 cc.retry_counter = try_count;
114 cc.max_retries = 1; ///< We do retries ourselves
115
116 return std::apply(
117 [redis, method, cc](auto&&... args) {
118 return (redis.get()->*method)(args..., cc);
119 },
120 args_tuple);
121 };
122 return utils::hedging::HedgeRequest(
123 impl::RedisRequestStrategy<RedisRequestType>(std::move(gen_request)),
124 hedging_settings);
125}
126
127} // namespace redis
128
129USERVER_NAMESPACE_END