From: Hans Fugal <fugalh@fb.com>
Date: Wed, 4 Feb 2015 20:55:23 +0000 (-0800)
Subject: Future<T>::onTimeout(Duration, function<T()>, Timekeeper*=nullptr)
X-Git-Tag: v0.25.0~21
X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=dc64cee6a121dd91f5e992c86b0db184b8220b98;p=folly.git

Future<T>::onTimeout(Duration, function<T()>, Timekeeper*=nullptr)

Summary:
(or func returns Future<T>)

Invoke and respond to a timeout with a callback, rather than using `within` and adding `onError` or `then` or something.

Test Plan: new tests

Reviewed By: davejwatson@fb.com

Subscribers: jsedgwick, yfeldblum, trunkagent, fugalh, exa, folly-diffs@

FB internal diff: D1763174

Tasks: 4548494

Signature: t1:1763174:1423074062:05cec1dfb1110b31b599033949ebe0ee70dd0552
---

diff --git a/folly/futures/Future-inl.h b/folly/futures/Future-inl.h
index 893aa020..c91ad190 100644
--- a/folly/futures/Future-inl.h
+++ b/folly/futures/Future-inl.h
@@ -282,6 +282,14 @@ Future<T>::onError(F&& func) {
   return f;
 }
 
+template <class T>
+template <class F>
+Future<T> Future<T>::onTimeout(Duration dur, F&& func, Timekeeper* tk) {
+  auto funcw = folly::makeMoveWrapper(std::forward<F>(func));
+  return within(dur, tk)
+    .onError([funcw](TimedOut const&) { return (*funcw)(); });
+}
+
 template <class T>
 typename std::add_lvalue_reference<T>::type Future<T>::value() {
   throwIfInvalid();
diff --git a/folly/futures/Future.h b/folly/futures/Future.h
index 3751b8a9..a97ebfd4 100644
--- a/folly/futures/Future.h
+++ b/folly/futures/Future.h
@@ -326,6 +326,22 @@ class Future {
     Future<T>>::type
   onError(F&& func);
 
+  /// Like onError, but for timeouts. example:
+  ///
+  ///   Future<int> f = makeFuture<int>(42)
+  ///     .delayed(long_time)
+  ///     .onTimeout(short_time,
+  ///       []() -> int{ return -1; });
+  ///
+  /// or perhaps
+  ///
+  ///   Future<int> f = makeFuture<int>(42)
+  ///     .delayed(long_time)
+  ///     .onTimeout(short_time,
+  ///       []() { return makeFuture<int>(some_exception); });
+  template <class F>
+  Future<T> onTimeout(Duration, F&& func, Timekeeper* = nullptr);
+
   /// This is not the method you're looking for.
   ///
   /// This needs to be public because it's used by make* and when*, and it's
diff --git a/folly/futures/test/TimekeeperTest.cpp b/folly/futures/test/TimekeeperTest.cpp
index c3e53d35..1a19613c 100644
--- a/folly/futures/test/TimekeeperTest.cpp
+++ b/folly/futures/test/TimekeeperTest.cpp
@@ -126,3 +126,43 @@ TEST(Timekeeper, futureWithinException) {
   auto f = p.getFuture().within(awhile, std::runtime_error("expected"));
   EXPECT_THROW(f.get(), std::runtime_error);
 }
+
+TEST(Timekeeper, onTimeout) {
+  bool flag = false;
+  makeFuture(42).delayed(one_ms)
+    .onTimeout(Duration(0), [&]{ flag = true; return -1; })
+    .get();
+  EXPECT_TRUE(flag);
+}
+
+TEST(Timekeeper, onTimeoutReturnsFuture) {
+  bool flag = false;
+  makeFuture(42).delayed(one_ms)
+    .onTimeout(Duration(0), [&]{ flag = true; return makeFuture(-1); })
+    .get();
+  EXPECT_TRUE(flag);
+}
+
+TEST(Timekeeper, onTimeoutVoid) {
+  makeFuture().delayed(one_ms)
+    .onTimeout(Duration(0), [&]{
+     });
+  makeFuture().delayed(one_ms)
+    .onTimeout(Duration(0), [&]{
+       return makeFuture<void>(std::runtime_error("expected"));
+     });
+  // just testing compilation here
+}
+
+// TODO(5921764)
+/*
+TEST(Timekeeper, onTimeoutPropagates) {
+  bool flag = false;
+  EXPECT_THROW(
+    makeFuture(42).delayed(one_ms)
+      .onTimeout(Duration(0), [&]{ flag = true; })
+      .get(),
+    TimedOut);
+  EXPECT_TRUE(flag);
+}
+*/