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
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)) {}
47 RedisRequestStrategy(RedisRequestStrategy&& other)
noexcept =
default;
51 std::optional<RequestType> Create(size_t try_count) {
52 return gen_callback_(try_count);
54 std::optional<std::chrono::milliseconds> ProcessReply(RequestType&& request) {
55 reply_ = std::move(request).Get();
58 std::optional<ReplyType> ExtractReply() {
return std::move(reply_); }
59 void Finish(RequestType&&) {}
64 std::optional<ReplyType> reply_;
69template <
typename RedisRequestType>
71 impl::RedisRequestStrategy<RedisRequestType>>;
73template <
typename RedisRequestType,
typename... Args,
74 typename M = RedisRequestType (storages::redis::Client::*)(
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;
88 [redis, method, cc](
auto&&... args) {
89 return (redis.get()->*method)(args..., cc);
93 return utils::hedging::HedgeRequestAsync(
94 impl::RedisRequestStrategy<RedisRequestType>(std::move(gen_request)),
98template <
typename RedisRequestType>
100 impl::RedisRequestStrategy<RedisRequestType>>;
102template <
typename RedisRequestType,
typename... Args,
103 typename M = RedisRequestType (storages::redis::Client::*)(
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;
117 [redis, method, cc](
auto&&... args) {
118 return (redis.get()->*method)(args..., cc);
122 return utils::hedging::HedgeRequest(
123 impl::RedisRequestStrategy<RedisRequestType>(std::move(gen_request)),
130template <
typename RedisRequestType,
typename... Args,
131 typename M = RedisRequestType (storages::redis::Client::*)(
138 std::vector<redis::impl::RedisRequestStrategy<RedisRequestType>> strategies;
139 strategies.reserve(args.size());
141 for (
auto&& arg : args) {
143 [redis, method, cc{std::move(cc)}, args_tuple{std::move(arg)}](
144 int try_count)
mutable -> std::optional<RedisRequestType> {
145 cc.retry_counter = try_count;
149 [redis, method, cc](
auto&&... args) {
150 return (redis.get()->*method)(args..., cc);
154 strategies.emplace_back(std::move(gen_request));
157 return utils::hedging::HedgeRequestsBulk(std::move(strategies),
164template <
typename RedisRequestType,
typename... Args,
165 typename M = RedisRequestType (storages::redis::Client::*)(
168 redis::impl::RedisRequestStrategy<RedisRequestType>>
173 std::vector<std::tuple<Args...>> args) {
174 using RequestStrategy = redis::impl::RedisRequestStrategy<RedisRequestType>;
175 std::vector<RequestStrategy> strategies;
176 strategies.reserve(args.size());
178 for (
auto&& arg : args) {
180 [redis, method, cc{std::move(cc)}, args_tuple{std::move(arg)}](
181 int try_count)
mutable -> std::optional<RedisRequestType> {
182 cc.retry_counter = try_count;
186 [redis, method, cc](
auto&&... args) {
187 return (redis.get()->*method)(args..., cc);
191 strategies.emplace_back(std::move(gen_request));
194 return utils::hedging::HedgeRequestsBulkAsync<RequestStrategy>(
195 std::move(strategies), hedging_settings);