2 * Copyright 2014 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include "folly/wangle/Executor.h"
20 #include "folly/wangle/Future.h"
21 #include "folly/Optional.h"
23 namespace folly { namespace wangle {
25 template <typename T> struct isLaterOrFuture;
26 template <typename T> struct isLater;
29 * Since wangle primitives (promise/future) are not thread safe, it is difficult
30 * to build complex asynchronous workflows. A Later allows you to build such a
31 * workflow before actually launching it so that continuations can be set in a
34 * The interface to add additional work is the same as future: a then() method
35 * that can take either a type T, a Future<T>, or a Later<T>
37 * Thread transitions are done by using executors and calling the via() method.
39 * Here is an example of a workflow:
41 * Later<ClientRequest> later(std::move(request));
43 * auto future = later.
45 * .then([=](Try<ClientRequest>&& t) { return doCpuWork(t.value()); })
47 * .then([=](Try<CpuResponse>&& t) { return doDiskWork(t.value()); })
48 * .via(serverExecutor)
49 * .then([=]Try<DiskResponse>&& t) { return sendClientResponse(t.value()); })
52 * Although this workflow traverses many threads, we are able to string
53 * continuations together in a threadsafe manner.
55 * Laters can also be used to wrap preexisting asynchronous modules that were
56 * not built with wangle in mind. You can create a Later with a function that
57 * takes a callback as input. The function will not actually be called until
58 * launch(), allowing you to string then() statements on top of the callback.
65 template <class U = void,
66 class = typename std::enable_if<std::is_void<U>::value>::type,
67 class = typename std::enable_if<std::is_same<T, U>::value>::type>
71 class = typename std::enable_if<!std::is_void<U>::value>::type,
72 class = typename std::enable_if<std::is_same<T, U>::value>::type>
73 explicit Later(U&& input);
76 * then() adds additional work to the end of the workflow. If the lambda
77 * provided to then() returns a future, that future must be fulfilled in the
78 * same thread of the last set executor (either at constructor or from a call
82 typename std::enable_if<
83 !isLaterOrFuture<typename std::result_of<F(Try<T>&&)>::type>::value,
84 Later<typename std::result_of<F(Try<T>&&)>::type> >::type
88 typename std::enable_if<
89 isFuture<typename std::result_of<F(Try<T>&&)>::type>::value,
90 Later<typename std::result_of<F(Try<T>&&)>::type::value_type> >::type
94 * If the function passed to then() returns a Later<T>, calls to then() will
95 * be chained to the new Later before launching the new Later.
97 * This can be used to build asynchronous modules that can be called from a
98 * user thread and completed in a callback thread. Callbacks can be set up
99 * ahead of time without thread safety issues.
101 * Using the Later(std::function<void(std::function<void(T&&)>)>&& fn)
102 * constructor, you can wrap existing asynchronous modules with a Later and
103 * can chain it to wangle asynchronous workflows via this call.
106 typename std::enable_if<
107 isLater<typename std::result_of<F(Try<T>&&)>::type>::value,
108 Later<typename std::result_of<F(Try<T>&&)>::type::value_type> >::type
112 * Resets the executor - all then() calls made after the call to via() will be
113 * made in the new executor.
115 Later<T> via(Executor* executor);
118 * Starts the workflow. The function provided in the constructor will be
119 * called in the executor provided in the constructor. All proximate then()
120 * calls will be made, potentially changing threads if a via() call is made.
121 * The future returned will be fulfilled in the last executor.
123 * Thread safety issues of Futures still apply. If you want to wait on the
124 * Future, it must be done in the thread that will fulfill it. If you do not
125 * plan to use the result of the Future, use fireAndForget()
130 * Same as launch, only no Future is returned. This guarantees thread safe
131 * cleanup of the internal Futures, even if the Later completes in a different
132 * thread than the thread that calls fireAndForget().
134 void fireAndForget();
137 Promise<void> starter_;
138 folly::Optional<Future<T>> future_;
142 explicit Later(Promise<void>&& starter);
150 #include "Later-inl.h"