userver
C++ Async Framework
Toggle main menu visibility
Loading...
Searching...
No Matches
background_task_storage.hpp
Go to the documentation of this file.
1
#
pragma
once
2
3
/// @file userver/concurrent/background_task_storage.hpp
4
/// @brief @copybrief concurrent::BackgroundTaskStorage
5
6
#
include
<
cstdint
>
7
#
include
<
utility
>
8
9
#
include
<
userver
/
engine
/
impl
/
detached_tasks_sync_block
.
hpp
>
10
#
include
<
userver
/
engine
/
task
/
task_processor_fwd
.
hpp
>
11
#
include
<
userver
/
utils
/
async
.
hpp
>
12
13
USERVER_NAMESPACE_BEGIN
14
15
namespace
concurrent
{
16
17
/// @ingroup userver_concurrency userver_containers
18
///
19
/// A version of concurrent::BackgroundTaskStorage for advanced use cases (e.g.
20
/// driver internals) that can take the ownership of any kind of task.
21
class
BackgroundTaskStorageCore
final
{
22
public
:
23
/// Creates an empty BTS.
24
BackgroundTaskStorageCore
();
25
26
BackgroundTaskStorageCore(BackgroundTaskStorageCore&&) =
delete
;
27
BackgroundTaskStorageCore& operator=(BackgroundTaskStorageCore&&) =
delete
;
28
~BackgroundTaskStorageCore();
29
30
/// @brief Explicitly cancel and wait for the tasks.
31
/// New tasks must not be launched after this call returns.
32
///
33
/// More precisely, new tasks must not be launched once this call is completed, but can be launched in the process
34
/// of waiting for the remaining tasks. This means that one detached task is allowed to spawn another detached
35
/// task into the same BTS, which will immediately be cancelled and for which this call will wait as well.
36
///
37
/// Can only be called from a coroutine.
38
void
CancelAndWait
()
noexcept
;
39
40
/// @brief Wait for the remaining tasks to complete without cancelling them.
41
/// New tasks must not be launched after this call returns.
42
///
43
/// More precisely, new tasks must not be launched once this call is completed, but can be launched in the process
44
/// of waiting for the remaining tasks. This means that one detached task is allowed to spawn another detached
45
/// task into the same BTS, for which this call will wait as well.
46
///
47
/// @note Running this method burns some CPU time (a few microseconds). Awaiting the tasks once on service
48
/// shutdown, or even periodically, is okay, but don't use `BackgroundTaskStorage` as a substitute
49
/// for `std::vector<Task>` in handlers, because it is less efficient.
50
///
51
/// Can only be called from a coroutine.
52
void
WaitAndDisposeSlow
()
noexcept
;
53
54
/// @brief Detaches task, allowing it to continue execution out of scope. It
55
/// will be cancelled and waited for on BTS destruction.
56
/// @note After detach, Task becomes invalid
57
///
58
/// Can be called from a coroutine or a non-coroutine thread.
59
/// Cannot be called after @ref CancelAndWait or @ref WaitAndDisposeSlow has been called.
60
void
Detach
(engine::
Task
&& task);
61
62
/// @returns Approximate number of currently active tasks.
63
///
64
/// Can be called from a coroutine or a non-coroutine thread.
65
/// Cannot be called after @ref CancelAndWait or @ref WaitAndDisposeSlow has been called.
66
std::
int64_t
ActiveTasksApprox
()
const
noexcept
;
67
68
private
:
69
std::optional<engine::
impl
::DetachedTasksSyncBlock> sync_block_;
70
};
71
72
/// @ingroup userver_concurrency userver_containers
73
///
74
/// A storage that allows one to start detached tasks; cancels and waits for
75
/// unfinished tasks completion at the destructor. Provides CancelAndWait to
76
/// explicitly cancel tasks (recommended).
77
///
78
/// Usable for detached tasks that capture references to resources with a
79
/// limited lifetime. You must guarantee that the resources are available while
80
/// the BackgroundTaskStorage is alive.
81
///
82
/// ## Performance considerations
83
///
84
/// Tasks remove themselves from the BackgroundTaskStorage on completion, so there is no memory leak.
85
///
86
/// @warning The implementation is optimized for spawning tasks. Waiting for remaining tasks may be slow CPU-wise.
87
/// As a guideline, do not create `BackgroundTaskStorage` instances for each request, use `std::vector<Task>`
88
/// for storing per-request child tasks instead.
89
///
90
/// ## Usage synopsis
91
///
92
/// @snippet core/src/concurrent/background_task_storage_test.cpp Sample
93
///
94
/// ## Lifetime of task's captures
95
///
96
/// All the advice from utils::Async is applicable here.
97
///
98
/// BackgroundTaskStorage is always stored as a class field. Tasks that are
99
/// launched inside it (or moved inside it, for BackgroundTaskStorageCore)
100
/// can safely access fields declared before it, but not after it:
101
///
102
/// @snippet core/src/concurrent/background_task_storage_test.cpp BtsLifetimeCapturesPitfalls
103
///
104
/// Generally, it's a good idea to declare `bts_` after most other fields
105
/// to avoid lifetime bugs. An example of fool-proof code:
106
///
107
/// @snippet core/src/concurrent/background_task_storage_test.cpp Bts field ordering
108
///
109
/// Components and their clients can always be safely captured by reference:
110
///
111
/// @see @ref scripts/docs/en/userver/component_system.md
112
///
113
/// So for a BackgroundTaskStorage stored in a component, its tasks can only
114
/// safely use the fields declared before the BTS field, as well as everything
115
/// from the components, on which the current component depends.
116
class
BackgroundTaskStorage
final
{
117
public
:
118
/// Creates a BTS that launches tasks in the engine::TaskProcessor used at the
119
/// BTS creation.
120
BackgroundTaskStorage
();
121
122
/// Creates a BTS that launches tasks in the specified engine::TaskProcessor.
123
explicit
BackgroundTaskStorage
(engine::TaskProcessor& task_processor);
124
125
BackgroundTaskStorage(
const
BackgroundTaskStorage&) =
delete
;
126
BackgroundTaskStorage& operator=(
const
BackgroundTaskStorage&) =
delete
;
127
128
/// @brief Explicitly cancel and wait for the tasks.
129
/// New tasks must not be launched after this call returns.
130
///
131
/// More precisely, new tasks must not be launched once this call is completed, but can be launched in the process
132
/// of waiting for the remaining tasks. This means that one detached task is allowed to spawn another detached
133
/// task into the same BTS, which will immediately be cancelled and for which this call will wait as well.
134
///
135
/// Can only be called from a coroutine.
136
void
CancelAndWait
()
noexcept
;
137
138
/// @brief Wait for the remaining tasks to complete without cancelling them.
139
/// New tasks must not be launched after this call returns.
140
///
141
/// More precisely, new tasks must not be launched once this call is completed, but can be launched in the process
142
/// of waiting for the remaining tasks. This means that one detached task is allowed to spawn another detached
143
/// task into the same BTS, for which this call will wait as well.
144
///
145
/// @note Running this method burns some CPU time (a few microseconds). Awaiting the tasks once on service
146
/// shutdown, or even periodically, is okay, but don't use `BackgroundTaskStorage` as a substitute
147
/// for `std::vector<Task>` in handlers, because it is less efficient.
148
///
149
/// Can only be called from a coroutine.
150
void
WaitAndDisposeSlow
()
noexcept
;
151
152
/// @brief Launch a task that will be cancelled and waited for in the BTS
153
/// destructor.
154
///
155
/// The task is started as non-Critical, it may be cancelled due to
156
/// `TaskProcessor` overload. engine::TaskInheritedVariable instances are not
157
/// inherited from the caller except baggage::Baggage. See
158
/// utils::AsyncBackground for details.
159
///
160
/// Can be called from a coroutine or a non-coroutine thread.
161
template
<
typename
... Args>
162
void
AsyncDetach
(std::string name, Args&&... args) {
163
core_
.
Detach
(
utils
::AsyncBackground(std::move(name), task_processor_, std::forward<Args>(args)...)
)
;
164
}
165
166
/// @brief Launch a task that will be cancelled and waited for in the BTS
167
/// destructor.
168
///
169
/// Execution of function is guaranteed to start regardless
170
/// of engine::TaskProcessor load limits.
171
/// engine::TaskInheritedVariable instances are not
172
/// inherited from the caller except baggage::Baggage. See
173
/// utils::CriticalAsyncBackground for details.
174
///
175
/// Can be called from a coroutine or a non-coroutine thread.
176
template
<
typename
... Args>
177
void
CriticalAsyncDetach
(std::string name, Args&&... args) {
178
core_
.
Detach
(
utils
::CriticalAsyncBackground(std::move(name), task_processor_, std::forward<Args>(args)...)
)
;
179
}
180
181
/// @returns Approximate number of currently active tasks.
182
///
183
/// Can be called from a coroutine or a non-coroutine thread.
184
/// Cannot be called after @ref CancelAndWait or @ref WaitAndDisposeSlow has been called.
185
std::
int64_t
ActiveTasksApprox
()
const
noexcept
;
186
187
private
:
188
BackgroundTaskStorageCore core_;
189
engine::TaskProcessor& task_processor_;
190
};
191
192
}
// namespace concurrent
193
194
USERVER_NAMESPACE_END
userver
concurrent
background_task_storage.hpp
Generated on
for userver by
Doxygen
1.17.0