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 callbacks can be set in a
34 * The interface to add additional work is the same as future: a then() method
35 * that takes a function that can return either a type T, a Future<T>, or a
38 * Thread transitions are done by using executors and calling the via() method.
40 * Here is an example of a workflow:
42 * Later<ClientRequest> later(std::move(request));
44 * auto future = later.
46 * .then([=](Try<ClientRequest>&& t) { return doCpuWork(t.value()); })
48 * .then([=](Try<CpuResponse>&& t) { return doDiskWork(t.value()); })
49 * .via(serverExecutor)
50 * .then([=]Try<DiskResponse>&& t) { return sendClientResponse(t.value()); })
53 * Although this workflow traverses many threads, we are able to string
54 * continuations together in a threadsafe manner.
56 * Laters can also be used to wrap preexisting asynchronous modules that were
57 * not built with wangle in mind. You can create a Later with a function that
58 * takes a callback as input. The function will not actually be called until
59 * launch(), allowing you to string then() statements on top of the callback.
67 * This default constructor is used to build an asynchronous workflow that
70 template <class U = void,
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>
76 * Lift a Future into a Later
78 /* implicit */ Later(Future<T>&& f);
81 * This constructor is used to build an asynchronous workflow that takes a
82 * value as input, and that value is passed in.
85 class = typename std::enable_if<!std::is_void<U>::value>::type,
86 class = typename std::enable_if<std::is_same<T, U>::value>::type>
87 explicit Later(U&& input);
90 * This constructor is used to wrap a pre-existing cob-style asynchronous api
91 * so that it can be used in wangle in a threadsafe manner. wangle provides
92 * the callback to this pre-existing api, and this callback will fulfill a
93 * promise so as to incorporate this api into the workflow.
97 * // This adds two ints asynchronously. cob is called in another thread.
98 * void addAsync(int a, int b, std::function<void(int&&)>&& cob);
100 * Later<int> asyncWrapper([=](std::function<void(int&&)>&& fn) {
101 * addAsync(1, 2, std::move(fn));
105 class = typename std::enable_if<!std::is_void<U>::value>::type,
106 class = typename std::enable_if<std::is_same<T, U>::value>::type>
107 explicit Later(std::function<void(std::function<void(U&&)>&&)>&& fn);
110 * then() adds additional work to the end of the workflow. If the lambda
111 * provided to then() returns a future, that future must be fulfilled in the
112 * same thread of the last set executor (either at constructor or from a call
116 typename std::enable_if<
117 !isLaterOrFuture<typename std::result_of<F(Try<T>&&)>::type>::value,
118 Later<typename std::result_of<F(Try<T>&&)>::type> >::type
122 typename std::enable_if<
123 isFuture<typename std::result_of<F(Try<T>&&)>::type>::value,
124 Later<typename std::result_of<F(Try<T>&&)>::type::value_type> >::type
128 * If the function passed to then() returns a Later<T>, calls to then() will
129 * be chained to the new Later before launching the new Later.
131 * This can be used to build asynchronous modules that can be called from a
132 * user thread and completed in a callback thread. Callbacks can be set up
133 * ahead of time without thread safety issues.
135 * Using the Later(std::function<void(std::function<void(T&&)>)>&& fn)
136 * constructor, you can wrap existing asynchronous modules with a Later and
137 * can chain it to wangle asynchronous workflows via this call.
140 typename std::enable_if<
141 isLater<typename std::result_of<F(Try<T>&&)>::type>::value,
142 Later<typename std::result_of<F(Try<T>&&)>::type::value_type> >::type
146 * Resets the executor - all then() calls made after the call to via() will be
147 * made in the new executor. The Executor must outlive.
149 Later<T> via(Executor* executor);
152 * Starts the workflow. The function provided in the constructor will be
153 * called in the executor provided in the constructor. Subsequent then()
154 * calls will be made, potentially changing threads if a via() call is made.
155 * The future returned will be fulfilled in the last executor.
157 * Thread safety issues of Futures still apply. If you want to wait on the
158 * Future, it must be done in the thread that will fulfil it.
163 * Same as launch, only no Future is returned. This guarantees thread safe
164 * cleanup of the internal Futures, even if the Later completes in a different
165 * thread than the thread that calls fireAndForget().
167 * Deprecated. Use launch()
169 void fireAndForget() { launch(); }
172 Promise<void> starter_;
173 folly::Optional<Future<T>> future_;
177 explicit Later(Promise<void>&& starter);
185 #include "Later-inl.h"