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