From dc64cee6a121dd91f5e992c86b0db184b8220b98 Mon Sep 17 00:00:00 2001 From: Hans Fugal Date: Wed, 4 Feb 2015 12:55:23 -0800 Subject: [PATCH] Future::onTimeout(Duration, function, Timekeeper*=nullptr) Summary: (or func returns Future) 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 | 8 ++++++ folly/futures/Future.h | 16 +++++++++++ folly/futures/test/TimekeeperTest.cpp | 40 +++++++++++++++++++++++++++ 3 files changed, 64 insertions(+) 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::onError(F&& func) { return f; } +template +template +Future Future::onTimeout(Duration dur, F&& func, Timekeeper* tk) { + auto funcw = folly::makeMoveWrapper(std::forward(func)); + return within(dur, tk) + .onError([funcw](TimedOut const&) { return (*funcw)(); }); +} + template typename std::add_lvalue_reference::type Future::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>::type onError(F&& func); + /// Like onError, but for timeouts. example: + /// + /// Future f = makeFuture(42) + /// .delayed(long_time) + /// .onTimeout(short_time, + /// []() -> int{ return -1; }); + /// + /// or perhaps + /// + /// Future f = makeFuture(42) + /// .delayed(long_time) + /// .onTimeout(short_time, + /// []() { return makeFuture(some_exception); }); + template + Future 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(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); +} +*/ -- 2.34.1