userver: userver/utils/task_builder.hpp Source File
Loading...
Searching...
No Matches
task_builder.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/utils/task_builder.hpp
4/// @brief @copybrief engine::TaskBuilder
5
6#include <variant>
7
8#include <userver/compiler/impl/lifetime.hpp>
9#include <userver/engine/async.hpp>
10#include <userver/engine/impl/task_context_factory.hpp>
11#include <userver/engine/task/shared_task_with_result.hpp>
12#include <userver/engine/task/task_with_result.hpp>
13#include <userver/utils/impl/span_wrap_call.hpp>
14#include <userver/utils/overloaded.hpp>
15
16USERVER_NAMESPACE_BEGIN
17
18namespace utils {
19
20/// Builder class for engine::Task and engine::TaskWithResult.
21/// Use it if you want to build a task with complex properties
22/// or even the property values are determined at runtime.
23/// If you just want to start a task, use @ref utils::Async
24/// or @ref engine::AsyncNoSpan.
25///
26/// @see @ref intro_tasks
27class TaskBuilder final {
28public:
29 TaskBuilder() = default;
30
31 TaskBuilder(const TaskBuilder&) = default;
32
33 TaskBuilder(TaskBuilder&&) = default;
34
35 TaskBuilder& operator=(const TaskBuilder&) = default;
36
37 TaskBuilder& operator=(TaskBuilder&&) = default;
38
39 /// Set "critical" flag for the new task.
40 /// @see @ref engine::TaskBase::Importance
41 TaskBuilder& Critical() USERVER_IMPL_LIFETIME_BOUND;
42
43 /// The following call to @ref Build will spawn a task with
44 /// @ref tracing::Span with the passed name.
45 TaskBuilder& SpanName(std::string&& name) USERVER_IMPL_LIFETIME_BOUND;
46
47 /// The following call to @ref Build will spawn a task with @ref tracing::Span,
48 /// but with @ref logging::Level::kNone log level (it hides the span log
49 /// itself, but not logs within the span). Logs will then be linked
50 /// to the nearest span that is written out.
51 TaskBuilder& HideSpan() USERVER_IMPL_LIFETIME_BOUND;
52
53 /// The following call to @ref Build will spawn a task without
54 /// any @ref tracing::Span.
55 /// @see @ref engine::AsyncNoSpan()
56 TaskBuilder& NoSpan() USERVER_IMPL_LIFETIME_BOUND;
57
58 /// The following call to @ref Build will spawn a task inside
59 /// the defined task processor. If not called,
60 /// @ref engine::current_task::GetTaskProcessor is used by default.
61 TaskBuilder& TaskProcessor(engine::TaskProcessor& tp) USERVER_IMPL_LIFETIME_BOUND;
62
63 /// The following call to @ref Build will spawn a task that has a defined deadline.
64 /// If the deadline expires, the task is cancelled.
65 /// See `*Async*` function signatures for details.
66 TaskBuilder& Deadline(engine::Deadline deadline) USERVER_IMPL_LIFETIME_BOUND;
67
68 /// The following call to @ref Build will spawn a background task
69 /// without propagating @ref engine::TaskInheritedVariable.
70 /// @ref tracing::Span and @ref baggage::Baggage are inherited.
71 TaskBuilder& Background() USERVER_IMPL_LIFETIME_BOUND;
72
73 /// Setup and return the task. It doesn't drop the previous settings,
74 /// so it can be called multiple times.
75 ///
76 /// By default, arguments are copied or moved inside the resulting
77 /// `TaskWithResult`, like `std::thread` does. To pass an argument by reference,
78 /// wrap it in `std::ref / std::cref` or capture the arguments using a lambda.
79 /// @returns engine::TaskWithResult
80 template <typename Function, typename... Args>
81 auto Build(Function&& f, Args&&... args);
82
83 /// Setup and return the task. It doesn't drop the previous settings,
84 /// so it can be called multiple times.
85 ///
86 /// By default, arguments are copied or moved inside the resulting
87 /// `TaskWithResult`, like `std::thread` does. To pass an argument by reference,
88 /// wrap it in `std::ref / std::cref` or capture the arguments using a lambda.
89 /// @returns engine::SharedTaskWithResult
90 template <typename Function, typename... Args>
91 auto BuildShared(Function&& f, Args&&... args);
92
93private:
94 engine::impl::TaskConfig MakeConfig() const;
95
96 auto MakeSpanFunctor(
97 std::string name,
98 utils::impl::SpanWrapCall::HideSpan hide_span,
99 const utils::impl::SourceLocation& location = utils::impl::SourceLocation::Current()
100 );
101
102 template <typename Task, typename Function, typename... Args>
103 Task BuildTask(Function&& f, Args&&... args);
104
105 struct NoSpanTag {};
106
107 struct HideSpanTag {};
108
109 // Note: do not use impl::TaskConfig as it stores a ref to TaskProcessor, which cannot be nullptr
110 engine::TaskProcessor* tp_{nullptr};
111 engine::Task::Importance importance_{engine::Task::Importance::kNormal};
112 engine::Task::WaitMode wait_mode_{engine::Task::WaitMode::kSingleWaiter};
113 engine::Deadline deadline_;
114 std::optional<std::variant<std::string, NoSpanTag, HideSpanTag>> span_;
115 utils::impl::SpanWrapCall::InheritVariables inherit_variables_{utils::impl::SpanWrapCall::InheritVariables::kYes};
116};
117
118inline auto TaskBuilder::MakeSpanFunctor(
119 std::string name,
120 utils::impl::SpanWrapCall::HideSpan hide_span,
121 const utils::impl::SourceLocation& location
122) {
123 return utils::impl::SpanLazyPrvalue(std::move(name), inherit_variables_, hide_span, location);
124}
125
126template <typename Function, typename... Args>
127auto TaskBuilder::Build(Function&& f, Args&&... args) {
128 using Task = engine::TaskWithResult<decltype(f(args...))>;
129 return BuildTask<Task>(std::forward<Function>(f), std::forward<Args>(args)...);
130}
131
132template <typename Function, typename... Args>
133auto TaskBuilder::BuildShared(Function&& f, Args&&... args) {
134 using Task = engine::SharedTaskWithResult<decltype(f(args...))>;
135 return BuildTask<Task>(std::forward<Function>(f), std::forward<Args>(args)...);
136}
137
138template <typename Task, typename Function, typename... Args>
139Task TaskBuilder::BuildTask(Function&& f, Args&&... args) {
141 span_, "Exactly one of the following methods of TaskBuilder must be called: SpanName(), NoSpan(), HideSpan()"
142 );
143
144 using HideSpan = utils::impl::SpanWrapCall::HideSpan;
145
146 return utils::Visit(
147 *span_,
148 [&](const std::string& name) {
149 return Task{engine::impl::MakeTask(
150 MakeConfig(),
151 MakeSpanFunctor({name}, HideSpan::kNo),
152 std::forward<Function>(f),
153 std::forward<Args>(args)...
154 )};
155 },
156 [&](NoSpanTag) {
157 return Task{engine::impl::MakeTask(MakeConfig(), std::forward<Function>(f), std::forward<Args>(args)...)};
158 },
159 [&](HideSpanTag) {
160 return Task{engine::impl::MakeTask(
161 MakeConfig(),
162 MakeSpanFunctor({}, HideSpan::kYes),
163 std::forward<Function>(f),
164 std::forward<Args>(args)...
165 )};
166 }
167 );
168}
169
170} // namespace utils
171
172USERVER_NAMESPACE_END