/*
- * Copyright 2015 Facebook, Inc.
+ * Copyright 2017 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#pragma once
#include <folly/futures/Future.h>
+#include <folly/Portability.h>
namespace folly {
/** Make a completed void Future. */
Future<Unit> makeFuture();
-/** Make a completed Future by executing a function. If the function throws
- we capture the exception, otherwise we capture the result. */
+/**
+ Make a Future by executing a function.
+
+ If the function returns a value of type T, makeFutureWith
+ returns a completed Future<T>, capturing the value returned
+ by the function.
+
+ If the function returns a Future<T> already, makeFutureWith
+ returns just that.
+
+ Either way, if the function throws, a failed Future is
+ returned that captures the exception.
+
+ Calling makeFutureWith(func) is equivalent to calling
+ makeFuture().then(func).
+*/
+
+// makeFutureWith(Future<T>()) -> Future<T>
+template <class F>
+typename std::enable_if<isFuture<typename std::result_of<F()>::type>::value,
+ typename std::result_of<F()>::type>::type
+makeFutureWith(F&& func);
+
+// makeFutureWith(T()) -> Future<T>
+// makeFutureWith(void()) -> Future<Unit>
template <class F>
-auto makeFutureWith(F&& func)
- -> Future<typename Unit::Lift<decltype(func())>::type>;
+typename std::enable_if<
+ !(isFuture<typename std::result_of<F()>::type>::value),
+ Future<typename Unit::Lift<typename std::result_of<F()>::type>::type>>::type
+makeFutureWith(F&& func);
/// Make a failed Future from an exception_ptr.
/// Because the Future's type cannot be inferred you have to specify it, e.g.
///
/// auto f = makeFuture<string>(std::current_exception());
template <class T>
-Future<T> makeFuture(std::exception_ptr const& e) DEPRECATED;
+FOLLY_DEPRECATED("use makeFuture(exception_wrapper)")
+Future<T> makeFuture(std::exception_ptr const& e);
/// Make a failed Future from an exception_wrapper.
template <class T>
/// This is semantically equivalent to via(executor).then(func), but
/// easier to read and slightly more efficient.
template <class Func>
-auto via(Executor*, Func func)
- -> Future<typename isFuture<decltype(func())>::Inner>;
+auto via(Executor*, Func&& func)
+ -> Future<typename isFuture<decltype(std::declval<Func>()())>::Inner>;
/** When all the input Futures complete, the returned Future will complete.
Errors do not cause early termination; this Future will always succeed
return collectAny(c.begin(), c.end());
}
+/** Similar to collectAny, collectAnyWithoutException return the first Future to
+ * complete without exceptions. If none of the future complete without
+ * excpetions, the last exception will be returned as a result.
+ */
+template <class InputIterator>
+Future<std::pair<
+ size_t,
+ typename std::iterator_traits<InputIterator>::value_type::value_type>>
+collectAnyWithoutException(InputIterator first, InputIterator last);
+
+/// Sugar for the most common case
+template <class Collection>
+auto collectAnyWithoutException(Collection&& c)
+ -> decltype(collectAnyWithoutException(c.begin(), c.end())) {
+ return collectAnyWithoutException(c.begin(), c.end());
+}
+
/** when n Futures have completed, the Future completes with a vector of
the index and Try of those n Futures (the indices refer to the original
order, but the result vector will be in an arbitrary order)
std::forward<F>(func));
}
+namespace futures {
+
+/**
+ * retrying
+ *
+ * Given a policy and a future-factory, creates futures according to the
+ * policy.
+ *
+ * The policy must be moveable - retrying will move it a lot - and callable of
+ * either of the two forms:
+ * - Future<bool>(size_t, exception_wrapper)
+ * - bool(size_t, exception_wrapper)
+ * Internally, the latter is transformed into the former in the obvious way.
+ * The first parameter is the attempt number of the next prospective attempt;
+ * the second parameter is the most recent exception. The policy returns a
+ * Future<bool> which, when completed with true, indicates that a retry is
+ * desired.
+ *
+ * We provide a few generic policies:
+ * - Basic
+ * - CappedJitteredexponentialBackoff
+ *
+ * Custom policies may use the most recent try number and exception to decide
+ * whether to retry and optionally to do something interesting like delay
+ * before the retry. Users may pass inline lambda expressions as policies, or
+ * may define their own data types meeting the above requirements. Users are
+ * responsible for managing the lifetimes of anything pointed to or referred to
+ * from inside the policy.
+ *
+ * For example, one custom policy may try up to k times, but only if the most
+ * recent exception is one of a few types or has one of a few error codes
+ * indicating that the failure was transitory.
+ *
+ * Cancellation is not supported.
+ *
+ * If both FF and Policy inline executes, then it is possible to hit a stack
+ * overflow due to the recursive nature of the retry implementation
+ */
+template <class Policy, class FF>
+typename std::result_of<FF(size_t)>::type
+retrying(Policy&& p, FF&& ff);
+
+/**
+ * generic retrying policies
+ */
+
+inline
+std::function<bool(size_t, const exception_wrapper&)>
+retryingPolicyBasic(
+ size_t max_tries);
+
+template <class Policy, class URNG>
+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);
+
+inline
+std::function<Future<bool>(size_t, const exception_wrapper&)>
+retryingPolicyCappedJitteredExponentialBackoff(
+ size_t max_tries,
+ Duration backoff_min,
+ Duration backoff_max,
+ double jitter_param);
+
+}
+
} // namespace