Future<T>::onTimeout(Duration, function<T()>, Timekeeper*=nullptr)
authorHans Fugal <fugalh@fb.com>
Wed, 4 Feb 2015 20:55:23 +0000 (12:55 -0800)
committerSara Golemon <sgolemon@fb.com>
Wed, 11 Feb 2015 02:01:59 +0000 (18:01 -0800)
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

folly/futures/Future-inl.h
folly/futures/Future.h
folly/futures/test/TimekeeperTest.cpp

index 893aa020f7ede3e89cef2c573d019da814809ccb..c91ad190d4eddede62494862fef3cc0dd365d06c 100644 (file)
@@ -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();
index 3751b8a90653c8f049278a83af259febb061ba78..a97ebfd4e19cc31b4eb6b1be53d0972074967a59 100644 (file)
@@ -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
index c3e53d359bb2e1b39cf452e2b03ebb8618f48099..1a19613cf3ed8708b707caab09c8d3b2b55edc9f 100644 (file)
@@ -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);
+}
+*/