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 {
39 using RequestType = RedisRequestType;
40 using ReplyType =
typename RequestType::Reply;
41 using GenF = std::function<std::optional<RequestType>(
int)>;
43 explicit RedisRequestStrategy(GenF gen_callback)
44 : gen_callback_(std::move(gen_callback))
47 RedisRequestStrategy(RedisRequestStrategy&& other)
noexcept =
default;
51 std::optional<RequestType> Create(size_t try_count) {
return gen_callback_(try_count); }
52 std::optional<std::chrono::milliseconds> ProcessReply(RequestType&& request) {
53 reply_ = std::move(request).Get();
56 std::optional<ReplyType> ExtractReply() {
return std::move(reply_); }
57 void Finish(RequestType&&) {}
62 std::optional<ReplyType> reply_;
67template <
typename RedisRequestType>
71 typename RedisRequestType,
73 typename M = RedisRequestType (storages::redis::Client::*)(Args...,
const redis::
CommandControl&)>
82 [redis, method, cc{std::move(cc)}, args_tuple{std::tuple(std::move(args)...)}](
int try_count
83 )
mutable -> std::optional<RedisRequestType> {
88 [redis, method, cc](
auto&&... args) {
return (redis.get()->*method)(args..., cc); },
92 return utils::hedging::HedgeRequestAsync(
93 impl::RedisRequestStrategy<RedisRequestType>(std::move(gen_request)),
98template <
typename RedisRequestType>
102 typename RedisRequestType,
104 typename M = RedisRequestType (storages::redis::Client::*)(Args...,
const redis::
CommandControl&)>
113 [redis, method, cc{std::move(cc)}, args_tuple{std::tuple(std::move(args)...)}](
int try_count
114 )
mutable -> std::optional<RedisRequestType> {
119 [redis, method, cc](
auto&&... args) {
return (redis.get()->*method)(args..., cc); },
123 return utils::hedging::HedgeRequest(
124 impl::RedisRequestStrategy<RedisRequestType>(std::move(gen_request)),
133 typename RedisRequestType,
135 typename M = RedisRequestType (storages::redis::Client::*)(Args...,
const redis::
CommandControl&)>
141 std::vector<std::tuple<Args...>> args
143 std::vector<
redis::impl::RedisRequestStrategy<RedisRequestType>> strategies;
144 strategies.reserve(args.size());
146 for (
auto&& arg : args) {
147 auto gen_request = [redis, method, cc{std::move(cc)}, args_tuple{std::move(arg)}](
int try_count)
mutable
148 -> std::optional<RedisRequestType> {
153 [redis, method, cc](
auto&&... args) {
return (redis.get()->*method)(args..., cc); },
157 strategies.emplace_back(std::move(gen_request));
160 return utils::hedging::HedgeRequestsBulk(std::move(strategies), hedging_settings);
167 typename RedisRequestType,
169 typename M = RedisRequestType (storages::redis::Client::*)(Args...,
const redis::
CommandControl&)>
176 std::vector<std::tuple<Args...>> args
178 using RequestStrategy =
redis::impl::RedisRequestStrategy<RedisRequestType>;
179 std::vector<RequestStrategy> strategies;
180 strategies.reserve(args.size());
182 for (
auto&& arg : args) {
183 auto gen_request = [redis, method, cc{std::move(cc)}, args_tuple{std::move(arg)}](
int try_count)
mutable
184 -> std::optional<RedisRequestType> {
189 [redis, method, cc](
auto&&... args) {
return (redis.get()->*method)(args..., cc); },
193 strategies.emplace_back(std::move(gen_request));
196 return utils::hedging::HedgeRequestsBulkAsync<RequestStrategy>(std::move(strategies), hedging_settings);