proxygen
Retrying.h
Go to the documentation of this file.
1 /*
2  * Copyright 2014-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <folly/Random.h>
21 #include <folly/futures/Future.h>
22 
23 namespace folly {
24 namespace futures {
25 
62 template <class Policy, class FF>
63 invoke_result_t<FF, size_t> retrying(Policy&& p, FF&& ff);
64 
65 namespace detail {
66 
69 
70 template <class Policy>
73  using is_raw = std::is_same<result, bool>;
74  using is_fut = std::is_same<result, Future<bool>>;
75  using tag = typename std::conditional<
78  typename std::conditional<is_fut::value, retrying_policy_fut_tag, void>::
80 };
81 
82 template <class Policy, class FF, class Prom>
83 void retryingImpl(size_t k, Policy&& p, FF&& ff, Prom prom) {
85  using T = typename F::value_type;
86  auto f = makeFutureWith([&] { return ff(k++); });
87  std::move(f).then([k,
88  prom = std::move(prom),
89  pm = std::forward<Policy>(p),
90  ffm = std::forward<FF>(ff)](Try<T>&& t) mutable {
91  if (t.hasValue()) {
92  prom.setValue(std::move(t).value());
93  return;
94  }
95  auto& x = t.exception();
96  auto q = makeFutureWith([&] { return pm(k, x); });
97  std::move(q).then([k,
98  prom = std::move(prom),
99  xm = std::move(x),
100  pm = std::move(pm),
101  ffm = std::move(ffm)](Try<bool> shouldRetry) mutable {
102  if (shouldRetry.hasValue() && shouldRetry.value()) {
103  retryingImpl(k, std::move(pm), std::move(ffm), std::move(prom));
104  } else if (shouldRetry.hasValue()) {
105  prom.setException(std::move(xm));
106  } else {
107  prom.setException(std::move(shouldRetry.exception()));
108  }
109  });
110  });
111 }
112 
113 template <class Policy, class FF>
114 invoke_result_t<FF, size_t> retrying(size_t k, Policy&& p, FF&& ff) {
115  using F = invoke_result_t<FF, size_t>;
116  using T = typename F::value_type;
117  auto prom = Promise<T>();
118  auto f = prom.getFuture();
119  retryingImpl(
120  k, std::forward<Policy>(p), std::forward<FF>(ff), std::move(prom));
121  return f;
122 }
123 
124 template <class Policy, class FF>
126 retrying(Policy&& p, FF&& ff, retrying_policy_raw_tag) {
127  auto q = [pm = std::forward<Policy>(p)](size_t k, exception_wrapper x) {
128  return makeFuture<bool>(pm(k, x));
129  };
130  return retrying(0, std::move(q), std::forward<FF>(ff));
131 }
132 
133 template <class Policy, class FF>
135 retrying(Policy&& p, FF&& ff, retrying_policy_fut_tag) {
136  return retrying(0, std::forward<Policy>(p), std::forward<FF>(ff));
137 }
138 
139 // jittered exponential backoff, clamped to [backoff_min, backoff_max]
140 template <class URNG>
142  size_t n,
143  Duration backoff_min,
144  Duration backoff_max,
145  double jitter_param,
146  URNG& rng) {
147  auto dist = std::normal_distribution<double>(0.0, jitter_param);
148  auto jitter = std::exp(dist(rng));
149  auto backoff_rep = jitter * backoff_min.count() * std::pow(2, n - 1);
150  if (UNLIKELY(backoff_rep >= std::numeric_limits<Duration::rep>::max())) {
151  return backoff_max;
152  }
153  auto backoff = Duration(Duration::rep(backoff_rep));
154  return std::max(backoff_min, std::min(backoff_max, backoff));
155 }
156 
157 template <class Policy, class URNG>
158 std::function<Future<bool>(size_t, const exception_wrapper&)>
160  size_t max_tries,
161  Duration backoff_min,
162  Duration backoff_max,
163  double jitter_param,
164  URNG&& rng,
165  Policy&& p) {
166  return [pm = std::forward<Policy>(p),
167  max_tries,
168  backoff_min,
169  backoff_max,
170  jitter_param,
171  rngp = std::forward<URNG>(rng)](
172  size_t n, const exception_wrapper& ex) mutable {
173  if (n == max_tries) {
174  return makeFuture(false);
175  }
176  return pm(n, ex).then(
177  [n, backoff_min, backoff_max, jitter_param, rngp = std::move(rngp)](
178  bool v) mutable {
179  if (!v) {
180  return makeFuture(false);
181  }
183  n, backoff_min, backoff_max, jitter_param, rngp);
184  return futures::sleep(backoff).thenValue([](auto&&) { return true; });
185  });
186  };
187 }
188 
189 template <class Policy, class URNG>
190 std::function<Future<bool>(size_t, const exception_wrapper&)>
192  size_t max_tries,
193  Duration backoff_min,
194  Duration backoff_max,
195  double jitter_param,
196  URNG&& rng,
197  Policy&& p,
199  auto q = [pm = std::forward<Policy>(p)](
200  size_t n, const exception_wrapper& e) {
201  return makeFuture(pm(n, e));
202  };
204  max_tries,
205  backoff_min,
206  backoff_max,
207  jitter_param,
208  std::forward<URNG>(rng),
209  std::move(q));
210 }
211 
212 template <class Policy, class URNG>
213 std::function<Future<bool>(size_t, const exception_wrapper&)>
215  size_t max_tries,
216  Duration backoff_min,
217  Duration backoff_max,
218  double jitter_param,
219  URNG&& rng,
220  Policy&& p,
223  max_tries,
224  backoff_min,
225  backoff_max,
226  jitter_param,
227  std::forward<URNG>(rng),
228  std::forward<Policy>(p));
229 }
230 
231 } // namespace detail
232 
233 template <class Policy, class FF>
234 invoke_result_t<FF, size_t> retrying(Policy&& p, FF&& ff) {
236  return detail::retrying(std::forward<Policy>(p), std::forward<FF>(ff), tag());
237 }
238 
239 inline std::function<bool(size_t, const exception_wrapper&)>
240 retryingPolicyBasic(size_t max_tries) {
241  return [=](size_t n, const exception_wrapper&) { return n < max_tries; };
242 }
243 
244 template <class Policy, class URNG>
245 std::function<Future<bool>(size_t, const exception_wrapper&)>
247  size_t max_tries,
248  Duration backoff_min,
249  Duration backoff_max,
250  double jitter_param,
251  URNG&& rng,
252  Policy&& p) {
255  max_tries,
256  backoff_min,
257  backoff_max,
258  jitter_param,
259  std::forward<URNG>(rng),
260  std::forward<Policy>(p),
261  tag());
262 }
263 
264 inline std::function<Future<bool>(size_t, const exception_wrapper&)>
266  size_t max_tries,
267  Duration backoff_min,
268  Duration backoff_max,
269  double jitter_param) {
270  auto p = [](size_t, const exception_wrapper&) { return true; };
272  max_tries,
273  backoff_min,
274  backoff_max,
275  jitter_param,
276  ThreadLocalPRNG(),
277  std::move(p));
278 }
279 
280 } // namespace futures
281 } // namespace folly
Definition: InvokeTest.cpp:58
std::function< Future< bool >size_t, const exception_wrapper &)> retryingPolicyCappedJitteredExponentialBackoff(size_t max_tries, Duration backoff_min, Duration backoff_max, double jitter_param, URNG &&rng, Policy &&p)
Definition: Retrying.h:159
auto f
typename std::conditional< is_raw::value, retrying_policy_raw_tag, typename std::conditional< is_fut::value, retrying_policy_fut_tag, void >::type >::type tag
Definition: Retrying.h:79
typename invoke_result< F, Args... >::type invoke_result_t
Definition: Invoke.h:142
LogLevel max
Definition: LogLevel.cpp:31
Duration retryingJitteredExponentialBackoffDur(size_t n, Duration backoff_min, Duration backoff_max, double jitter_param, URNG &rng)
Definition: Retrying.h:141
invoke_result_t< FF, size_t > retrying(size_t k, Policy &&p, FF &&ff)
Definition: Retrying.h:114
PskType type
Future< Unit > sleep(Duration dur, Timekeeper *tk)
Definition: Future.cpp:42
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
std::is_same< result, bool > is_raw
Definition: Retrying.h:73
folly::std T
exception_wrapper & exception()&
Definition: Try.h:260
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
auto rng
Definition: CollectTest.cpp:31
std::chrono::milliseconds Duration
Definition: Types.h:36
LogLevel min
Definition: LogLevel.cpp:30
void retryingImpl(size_t k, Policy &&p, FF &&ff, Prom prom)
Definition: Retrying.h:83
std::uniform_int_distribution< milliseconds::rep > dist
static const char *const value
Definition: Conv.cpp:50
Definition: Try.h:51
invoke_result_t< Policy, size_t, const exception_wrapper & > result
Definition: Retrying.h:72
bool hasValue() const
Definition: Try.h:242
std::function< bool(size_t, const exception_wrapper &)> retryingPolicyBasic(size_t max_tries)
Definition: Retrying.h:240
uint64_t value(const typename LockFreeRingBuffer< T, Atom >::Cursor &rbcursor)
T & value()&
Definition: Try-inl.h:140
#define UNLIKELY(x)
Definition: Likely.h:48
KeyT k
Future< typename std::decay< T >::type > makeFuture(T &&t)
Definition: Future-inl.h:1310
std::enable_if< isFuture< invoke_result_t< F > >::value, invoke_result_t< F > >::type makeFutureWith(F &&func)
Definition: Future-inl.h:1322
invoke_result_t< FF, size_t > retrying(Policy &&p, FF &&ff)
Definition: Retrying.h:234
std::is_same< result, Future< bool >> is_fut
Definition: Retrying.h:74