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