28#include <userver/storages/redis/client.hpp>
29#include <userver/storages/redis/command_control.hpp>
30#include <userver/utils/hedged_request.hpp>
32USERVER_NAMESPACE_BEGIN
34namespace storages::
redis {
37template <
typename RedisRequestType>
38struct RedisRequestStrategy {
40 using RequestType = RedisRequestType;
41 using ReplyType =
typename RequestType::Reply;
42 using GenF = std::function<std::optional<RequestType>(
int)>;
44 explicit RedisRequestStrategy(GenF gen_callback)
45 : gen_callback_(std::move(gen_callback))
48 RedisRequestStrategy(RedisRequestStrategy&& other)
noexcept =
default;
52 std::optional<RequestType> Create(size_t try_count) {
return gen_callback_(try_count); }
53 std::optional<std::chrono::milliseconds> ProcessReply(RequestType&& request) {
54 reply_ = std::move(request).Get();
57 std::optional<ReplyType> ExtractReply() {
return std::move(reply_); }
58 void Finish(RequestType&&) {}
63 std::optional<ReplyType> reply_;
68template <
typename RedisRequestType>
69using HedgedRedisRequest = utils::hedging::
HedgedRequestFuture<impl::RedisRequestStrategy<RedisRequestType>>;
72 typename RedisRequestType,
74 typename M = RedisRequestType (storages::redis::Client::*)(Args...,
const redis::
CommandControl&)>
83 [redis, method, cc{std::move(cc)}, args_tuple{std::tuple(std::move(args)...)}](
int try_count
84 )
mutable -> std::optional<RedisRequestType> {
89 [redis, method, cc](
auto&&... args) {
return (redis.get()->*method)(args..., cc); },
93 return utils::hedging::HedgeRequestAsync(
94 impl::RedisRequestStrategy<RedisRequestType>(std::move(gen_request)),
99template <
typename RedisRequestType>
100using HedgedRedisRequest = utils::hedging::
HedgedRequestFuture<impl::RedisRequestStrategy<RedisRequestType>>;
103 typename RedisRequestType,
105 typename M = RedisRequestType (storages::redis::Client::*)(Args...,
const redis::
CommandControl&)>
114 [redis, method, cc{std::move(cc)}, args_tuple{std::tuple(std::move(args)...)}](
int try_count
115 )
mutable -> std::optional<RedisRequestType> {
120 [redis, method, cc](
auto&&... args) {
return (redis.get()->*method)(args..., cc); },
124 return utils::hedging::HedgeRequest(
125 impl::RedisRequestStrategy<RedisRequestType>(std::move(gen_request)),
134 typename RedisRequestType,
136 typename M = RedisRequestType (storages::redis::Client::*)(Args...,
const redis::
CommandControl&)>
142 std::vector<std::tuple<Args...>> args
144 std::vector<
redis::impl::RedisRequestStrategy<RedisRequestType>> strategies;
145 strategies.reserve(args.size());
147 for (
auto&& arg : args) {
148 auto gen_request = [redis, method, cc{std::move(cc)}, args_tuple{std::move(arg)}](
int try_count)
mutable
149 -> std::optional<RedisRequestType> {
154 [redis, method, cc](
auto&&... args) {
return (redis.get()->*method)(args..., cc); },
158 strategies.emplace_back(std::move(gen_request));
161 return utils::hedging::HedgeRequestsBulk(std::move(strategies), hedging_settings);
168 typename RedisRequestType,
170 typename M = RedisRequestType (storages::redis::Client::*)(Args...,
const redis::
CommandControl&)>
177 std::vector<std::tuple<Args...>> args
179 using RequestStrategy =
redis::impl::RedisRequestStrategy<RedisRequestType>;
180 std::vector<RequestStrategy> strategies;
181 strategies.reserve(args.size());
183 for (
auto&& arg : args) {
184 auto gen_request = [redis, method, cc{std::move(cc)}, args_tuple{std::move(arg)}](
int try_count)
mutable
185 -> std::optional<RedisRequestType> {
190 [redis, method, cc](
auto&&... args) {
return (redis.get()->*method)(args..., cc); },
194 strategies.emplace_back(std::move(gen_request));
197 return utils::hedging::HedgeRequestsBulkAsync<RequestStrategy>(std::move(strategies), hedging_settings);