userver: userver/utils/async.hpp Source File
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
async.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/utils/async.hpp
4/// @brief Utility functions to start asynchronous tasks.
5
6#include <functional>
7#include <string>
8#include <utility>
9
10#include <userver/engine/async.hpp>
11#include <userver/utils/fast_pimpl.hpp>
12#include <userver/utils/lazy_prvalue.hpp>
13
14USERVER_NAMESPACE_BEGIN
15
16namespace utils {
17
18namespace impl {
19
20// A wrapper that obtains a Span from args, attaches it to current coroutine,
21// and applies a function to the rest of arguments.
22struct SpanWrapCall {
23 enum class InheritVariables { kYes, kNo };
24
25 explicit SpanWrapCall(std::string&& name, InheritVariables inherit_variables);
26
27 SpanWrapCall(const SpanWrapCall&) = delete;
28 SpanWrapCall(SpanWrapCall&&) = delete;
29 SpanWrapCall& operator=(const SpanWrapCall&) = delete;
30 SpanWrapCall& operator=(SpanWrapCall&&) = delete;
31 ~SpanWrapCall();
32
33 template <typename Function, typename... Args>
34 auto operator()(Function&& f, Args&&... args) {
35 DoBeforeInvoke();
36 return std::invoke(std::forward<Function>(f), std::forward<Args>(args)...);
37 }
38
39private:
40 void DoBeforeInvoke();
41
42 struct Impl;
43
44 static constexpr std::size_t kImplSize = 4280;
45 static constexpr std::size_t kImplAlign = 8;
46 utils::FastPimpl<Impl, kImplSize, kImplAlign> pimpl_;
47};
48
49// Note: 'name' must outlive the result of this function
50inline auto SpanLazyPrvalue(std::string&& name) {
51 return utils::LazyPrvalue([&name] { return SpanWrapCall(std::move(name), SpanWrapCall::InheritVariables::kYes); });
52}
53
54} // namespace impl
55
56/// @ingroup userver_concurrency
57///
58/// @brief Starts an asynchronous task.
59///
60/// By default, arguments are copied or moved inside the resulting
61/// `TaskWithResult`, like `std::thread` does. To pass an argument by reference,
62/// wrap it in `std::ref / std::cref` or capture the arguments using a lambda.
63///
64/// For more documentation on launching asynchronous tasks:
65///
66/// @see @ref intro_tasks
67///
68/// ## About this specific overload
69///
70/// This is the overload that should be used by default.
71///
72/// * The task will be launched on the current TaskProcessor.
73/// * Only 1 task may call `Wait` or `Get` on this task.
74/// * The task may be cancelled before the function starts execution
75/// in case of TaskProcessor overload. Also, if the task is cancelled for any
76/// reason before the function starts execution, it will not run at all.
77/// * The task will create a child tracing::Span with the specified name
78/// * The task will inherit all engine::TaskInheritedVariable instances
79/// from the current task.
80///
81/// For details on the various other overloads:
82/// @see @ref flavors_of_async
83///
84/// @param name Name of the task to show in logs
85/// @param f Function to execute asynchronously
86/// @param args Arguments to pass to the function
87/// @returns engine::TaskWithResult
88template <typename Function, typename... Args>
89[[nodiscard]] auto Async(std::string name, Function&& f, Args&&... args) {
90 return engine::AsyncNoSpan(
92 impl::SpanLazyPrvalue(std::move(name)),
93 std::forward<Function>(f),
94 std::forward<Args>(args)...
95 );
96}
97
98/// @overload
99/// @ingroup userver_concurrency
100///
101/// Task execution may be cancelled before the function starts execution
102/// in case of TaskProcessor overload.
103///
104/// @param task_processor Task processor to run on
105/// @param name Name of the task to show in logs
106/// @param f Function to execute asynchronously
107/// @param args Arguments to pass to the function
108/// @returns engine::TaskWithResult
109template <typename Function, typename... Args>
110[[nodiscard]] auto Async(engine::TaskProcessor& task_processor, std::string name, Function&& f, Args&&... args) {
111 return engine::AsyncNoSpan(
112 task_processor, impl::SpanLazyPrvalue(std::move(name)), std::forward<Function>(f), std::forward<Args>(args)...
113 );
114}
115
116/// @overload
117/// @ingroup userver_concurrency
118///
119/// Execution of function is guaranteed to start regardless
120/// of engine::TaskProcessor load limits. Prefer utils::Async by default.
121///
122/// @param task_processor Task processor to run on
123/// @param name Name for the tracing::Span to use with this task
124/// @param f Function to execute asynchronously
125/// @param args Arguments to pass to the function
126/// @returns engine::TaskWithResult
127template <typename Function, typename... Args>
128[[nodiscard]] auto
129CriticalAsync(engine::TaskProcessor& task_processor, std::string name, Function&& f, Args&&... args) {
130 return engine::CriticalAsyncNoSpan(
131 task_processor, impl::SpanLazyPrvalue(std::move(name)), std::forward<Function>(f), std::forward<Args>(args)...
132 );
133}
134
135/// @overload
136/// @ingroup userver_concurrency
137///
138/// Execution of function is guaranteed to start regardless
139/// of engine::TaskProcessor load limits. Prefer utils::SharedAsync by default.
140///
141/// @param task_processor Task processor to run on
142/// @param name Name for the tracing::Span to use with this task
143/// @param f Function to execute asynchronously
144/// @param args Arguments to pass to the function
145/// @returns engine::SharedTaskWithResult
146template <typename Function, typename... Args>
147[[nodiscard]] auto
148SharedCriticalAsync(engine::TaskProcessor& task_processor, std::string name, Function&& f, Args&&... args) {
149 return engine::SharedCriticalAsyncNoSpan(
150 task_processor, impl::SpanLazyPrvalue(std::move(name)), std::forward<Function>(f), std::forward<Args>(args)...
151 );
152}
153
154/// @overload
155/// @ingroup userver_concurrency
156///
157/// Task execution may be cancelled before the function starts execution
158/// in case of TaskProcessor overload.
159///
160/// @param task_processor Task processor to run on
161/// @param name Name of the task to show in logs
162/// @param f Function to execute asynchronously
163/// @param args Arguments to pass to the function
164/// @returns engine::SharedTaskWithResult
165template <typename Function, typename... Args>
166[[nodiscard]] auto SharedAsync(engine::TaskProcessor& task_processor, std::string name, Function&& f, Args&&... args) {
167 return engine::SharedAsyncNoSpan(
168 task_processor, impl::SpanLazyPrvalue(std::move(name)), std::forward<Function>(f), std::forward<Args>(args)...
169 );
170}
171
172/// @overload
173/// @ingroup userver_concurrency
174///
175/// Task execution may be cancelled before the function starts execution
176/// in case of TaskProcessor overload.
177///
178/// @param task_processor Task processor to run on
179/// @param name Name of the task to show in logs
180/// @param deadline Deadline to set for the child task, upon reaching it the task will be cancelled
181/// @param f Function to execute asynchronously
182/// @param args Arguments to pass to the function
183/// @returns engine::TaskWithResult
184template <typename Function, typename... Args>
185[[nodiscard]] auto Async(
186 engine::TaskProcessor& task_processor,
187 std::string name,
188 engine::Deadline deadline,
189 Function&& f,
190 Args&&... args
191) {
192 return engine::AsyncNoSpan(
193 task_processor,
194 deadline,
195 impl::SpanLazyPrvalue(std::move(name)),
196 std::forward<Function>(f),
197 std::forward<Args>(args)...
198 );
199}
200
201/// @overload
202/// @ingroup userver_concurrency
203///
204/// Task execution may be cancelled before the function starts execution
205/// in case of TaskProcessor overload.
206///
207/// @param task_processor Task processor to run on
208/// @param name Name of the task to show in logs
209/// @param deadline Deadline to set for the child task, upon reaching it the task will be cancelled
210/// @param f Function to execute asynchronously
211/// @param args Arguments to pass to the function
212/// @returns engine::SharedTaskWithResult
213template <typename Function, typename... Args>
214[[nodiscard]] auto SharedAsync(
215 engine::TaskProcessor& task_processor,
216 std::string name,
217 engine::Deadline deadline,
218 Function&& f,
219 Args&&... args
220) {
221 return engine::SharedAsyncNoSpan(
222 task_processor,
223 deadline,
224 impl::SpanLazyPrvalue(std::move(name)),
225 std::forward<Function>(f),
226 std::forward<Args>(args)...
227 );
228}
229
230/// @overload
231/// @ingroup userver_concurrency
232///
233/// Execution of function is guaranteed to start regardless
234/// of engine::TaskProcessor load limits. Prefer utils::Async by default.
235///
236/// @param name Name for the tracing::Span to use with this task
237/// @param f Function to execute asynchronously
238/// @param args Arguments to pass to the function
239/// @returns engine::TaskWithResult
240template <typename Function, typename... Args>
241[[nodiscard]] auto CriticalAsync(std::string name, Function&& f, Args&&... args) {
242 return utils::CriticalAsync(
244 std::move(name),
245 std::forward<Function>(f),
246 std::forward<Args>(args)...
247 );
248}
249
250/// @overload
251/// @ingroup userver_concurrency
252///
253/// Execution of function is guaranteed to start regardless
254/// of engine::TaskProcessor load limits. Prefer utils::SharedAsync by default.
255///
256/// @param name Name for the tracing::Span to use with this task
257/// @param f Function to execute asynchronously
258/// @param args Arguments to pass to the function
259/// @returns engine::SharedTaskWithResult
260template <typename Function, typename... Args>
261[[nodiscard]] auto SharedCriticalAsync(std::string name, Function&& f, Args&&... args) {
262 return utils::SharedCriticalAsync(
264 std::move(name),
265 std::forward<Function>(f),
266 std::forward<Args>(args)...
267 );
268}
269
270/// @overload
271/// @ingroup userver_concurrency
272///
273/// Task execution may be cancelled before the function starts execution
274/// in case of TaskProcessor overload.
275///
276/// @param name Name of the task to show in logs
277/// @param f Function to execute asynchronously
278/// @param args Arguments to pass to the function
279/// @returns engine::SharedTaskWithResult
280template <typename Function, typename... Args>
281[[nodiscard]] auto SharedAsync(std::string name, Function&& f, Args&&... args) {
282 return utils::SharedAsync(
284 std::move(name),
285 std::forward<Function>(f),
286 std::forward<Args>(args)...
287 );
288}
289
290/// @overload
291/// @ingroup userver_concurrency
292///
293/// Task execution may be cancelled before the function starts execution
294/// in case of TaskProcessor overload.
295///
296/// @param name Name of the task to show in logs
297/// @param deadline Deadline to set for the child task, upon reaching it the task will be cancelled
298/// @param f Function to execute asynchronously
299/// @param args Arguments to pass to the function
300/// @returns engine::TaskWithResult
301template <typename Function, typename... Args>
302[[nodiscard]] auto Async(std::string name, engine::Deadline deadline, Function&& f, Args&&... args) {
303 return utils::Async(
305 std::move(name),
306 deadline,
307 std::forward<Function>(f),
308 std::forward<Args>(args)...
309 );
310}
311
312/// @overload
313/// @ingroup userver_concurrency
314///
315/// Task execution may be cancelled before the function starts execution
316/// in case of TaskProcessor overload.
317///
318/// @param name Name of the task to show in logs
319/// @param deadline Deadline to set for the child task, upon reaching it the task will be cancelled
320/// @param f Function to execute asynchronously
321/// @param args Arguments to pass to the function
322/// @returns engine::SharedTaskWithResult
323template <typename Function, typename... Args>
324[[nodiscard]] auto SharedAsync(std::string name, engine::Deadline deadline, Function&& f, Args&&... args) {
325 return utils::SharedAsync(
327 std::move(name),
328 deadline,
329 std::forward<Function>(f),
330 std::forward<Args>(args)...
331 );
332}
333
334/// @ingroup userver_concurrency
335///
336/// Starts an asynchronous task without propagating
337/// engine::TaskInheritedVariable. tracing::Span and baggage::Baggage are
338/// inherited. Task execution may be cancelled before the function starts
339/// execution in case of engine::TaskProcessor overload.
340///
341/// Typically used from a request handler to launch tasks that outlive the
342/// request and do not effect its completion.
343///
344/// ## Usage example
345/// Suppose you have some component that runs asynchronous tasks:
346/// @snippet utils/async_test.cpp AsyncBackground component
347/// @snippet utils/async_test.cpp AsyncBackground handler
348///
349/// If the tasks logically belong to the component itself (not to the method
350/// caller), then they should be launched using utils::AsyncBackground instead
351/// of the regular utils::Async
352/// @snippet utils/async_test.cpp AsyncBackground FooAsync
353///
354/// ## Arguments
355/// By default, arguments are copied or moved inside the resulting
356/// `TaskWithResult`, like `std::thread` does. To pass an argument by reference,
357/// wrap it in `std::ref / std::cref` or capture the arguments using a lambda.
358///
359/// @param name Name of the task to show in logs
360/// @param task_processor Task processor to run on
361/// @param f Function to execute asynchronously
362/// @param args Arguments to pass to the function
363/// @returns engine::TaskWithResult
364template <typename Function, typename... Args>
365[[nodiscard]] auto
366AsyncBackground(std::string name, engine::TaskProcessor& task_processor, Function&& f, Args&&... args) {
367 return engine::AsyncNoSpan(
368 task_processor,
369 utils::LazyPrvalue([&] {
370 return impl::SpanWrapCall(std::move(name), impl::SpanWrapCall::InheritVariables::kNo);
371 }),
372 std::forward<Function>(f),
373 std::forward<Args>(args)...
374 );
375}
376
377/// @overload
378/// @ingroup userver_concurrency
379///
380/// Execution of function is guaranteed to start regardless
381/// of engine::TaskProcessor load limits. Use for background tasks for which
382/// failing to start not just breaks handling of a single request, but harms
383/// the whole service instance.
384///
385/// @param name Name of the task to show in logs
386/// @param task_processor Task processor to run on
387/// @param f Function to execute asynchronously
388/// @param args Arguments to pass to the function
389/// @returns engine::TaskWithResult
390template <typename Function, typename... Args>
391[[nodiscard]] auto
392CriticalAsyncBackground(std::string name, engine::TaskProcessor& task_processor, Function&& f, Args&&... args) {
393 return engine::CriticalAsyncNoSpan(
394 task_processor,
395 utils::LazyPrvalue([&] {
396 return impl::SpanWrapCall(std::move(name), impl::SpanWrapCall::InheritVariables::kNo);
397 }),
398 std::forward<Function>(f),
399 std::forward<Args>(args)...
400 );
401}
402
403} // namespace utils
404
405USERVER_NAMESPACE_END