userver
C++ Async Framework
Toggle main menu visibility
Loading...
Searching...
No Matches
source.hpp
Go to the documentation of this file.
1
#
pragma
once
2
3
/// @file userver/dynamic_config/source.hpp
4
/// @brief @copybrief dynamic_config::Source
5
6
#
include
<
optional
>
7
#
include
<
string_view
>
8
#
include
<
utility
>
9
10
#
include
<
userver
/
compiler
/
impl
/
lifetime
.
hpp
>
11
#
include
<
userver
/
concurrent
/
async_event_source
.
hpp
>
12
#
include
<
userver
/
dynamic_config
/
snapshot
.
hpp
>
13
#
include
<
userver
/
utils
/
assert
.
hpp
>
14
#
include
<
userver
/
utils
/
resource_scopes_fwd
.
hpp
>
15
16
USERVER_NAMESPACE_BEGIN
17
18
namespace
dynamic_config {
19
20
/// Owns a snapshot of a config variable. You may use operator* or operator->
21
/// to access the config variable.
22
template
<
typename
VariableType>
23
class
VariableSnapshotPtr
final
{
24
public
:
25
VariableSnapshotPtr(VariableSnapshotPtr&&) =
delete
;
26
VariableSnapshotPtr& operator=(VariableSnapshotPtr&&) =
delete
;
27
28
const
VariableType& operator*()
const
& USERVER_IMPL_LIFETIME_BOUND {
return
*variable_; }
29
const
VariableType& operator*() && { ReportMisuse(); }
30
31
const
VariableType* operator->()
const
& USERVER_IMPL_LIFETIME_BOUND {
return
variable_; }
32
const
VariableType* operator->() && { ReportMisuse(); }
33
34
private
:
35
[[noreturn]]
static
void
ReportMisuse() {
36
static_assert
(!
sizeof
(VariableType),
"keep the pointer before using, please"
);
37
}
38
39
explicit
VariableSnapshotPtr(Snapshot&& snapshot,
const
Key
<VariableType>& key)
40
: snapshot_(std::move(snapshot)),
41
variable_(&snapshot_[key])
42
{}
43
44
// for the constructor
45
friend
class
Source;
46
47
Snapshot snapshot_;
48
const
VariableType* variable_;
49
};
50
51
/// @brief Helper class for subscribing to dynamic-config updates with a custom
52
/// callback.
53
///
54
/// Stores information about the last update that occurred.
55
///
56
/// @param previous `dynamic_config::Snapshot` of the previous config or
57
/// `std::nullopt` if this update event is the first for the subscriber.
58
struct
Diff
final
{
59
std::optional<Snapshot> previous;
60
Snapshot current;
61
62
template
<
typename
... Keys>
63
bool
HasConfigsChanged(
const
Keys&... keys)
const
{
64
if
(!previous) {
65
return
true
;
66
}
67
68
UASSERT
(!current.GetData().IsEmpty());
69
UASSERT
(!previous->GetData().IsEmpty());
70
71
const
bool
is_equal = (
true
&& ... && ((*previous)[keys] == current[keys]));
72
return
!is_equal;
73
}
74
};
75
76
/// @ingroup userver_clients
77
///
78
/// @brief A client for easy dynamic config fetching in components.
79
///
80
/// After construction, dynamic_config::Source
81
/// can be copied around and passed to clients or child helper classes.
82
///
83
/// Usually retrieved from components::DynamicConfig component.
84
///
85
/// Typical usage:
86
/// @snippet core/src/components/component_sample_test.cpp Sample user component runtime config source
87
class
Source
final
{
88
public
:
89
using
SnapshotEventSource =
concurrent
::
AsyncEventSource
<
const
Snapshot&>;
90
using
DiffEventSource =
concurrent
::
AsyncEventSource
<
const
Diff&>;
91
92
/// For internal use only. Obtain using components::DynamicConfig or
93
/// dynamic_config::StorageMock instead.
94
explicit
Source
(impl::StorageData& storage);
95
96
// trivially copyable
97
Source(
const
Source&) =
default
;
98
Source(Source&&) =
default
;
99
Source& operator=(
const
Source&) =
default
;
100
Source& operator=(Source&&) =
default
;
101
102
Snapshot GetSnapshot()
const
;
103
104
template
<
typename
VariableType>
105
VariableSnapshotPtr<VariableType> GetSnapshot(
const
Key
<VariableType>& key)
const
{
106
return
VariableSnapshotPtr{GetSnapshot(), key};
107
}
108
109
template
<
typename
VariableType>
110
VariableType GetCopy(
const
Key
<VariableType>& key)
const
{
111
const
auto
snapshot = GetSnapshot();
112
return
snapshot[key];
113
}
114
115
/// Subscribes to dynamic-config updates using a member function. Also
116
/// immediately invokes the function with the current config snapshot (this
117
/// invocation will be executed synchronously).
118
///
119
/// Further updates are delivered after @ref utils::ResourceScopeStorage::AfterConstruction, including those updates
120
/// that arrived before it. Unsubscribe runs in @ref utils::ResourceScopeStorage::BeforeDestruction.
121
///
122
/// @note Callbacks occur in full accordance with
123
/// `components::DynamicConfigClientUpdater` options.
124
///
125
/// @param scopes storage that owns the subscription lifetime. In a component constructor pass `context.Scopes()`
126
/// or @ref components::GetResourceScopes.
127
/// @param obj the subscriber, which is the owner of the listener method, and
128
/// is also used as the unique identifier of the subscription
129
/// @param name the name of the subscriber, for diagnostic purposes
130
/// @param func the listener method, named `OnConfigUpdate` by convention.
131
///
132
/// @see based on concurrent::AsyncEventSource engine
133
template
<
typename
Class>
134
void
UpdateAndListen
(
135
utils
::ResourceScopeStorage& scopes,
136
Class* obj,
137
std::string_view name,
138
void
(Class::*func)(
const
dynamic_config::Snapshot& config)
139
) {
140
DoUpdateAndListen(
141
scopes,
142
concurrent
::FunctionId(obj),
143
name,
144
[obj, func](
const
dynamic_config::Snapshot& config) { (obj->*func)(config); }
145
);
146
}
147
148
/// @overload
149
/// @deprecated Use the overloads that take @ref utils::ResourceScopeStorage.
150
///
151
/// Store the returned scope as a member and call `Unsubscribe` explicitly.
152
template
<
typename
Class>
153
concurrent
::AsyncEventSubscriberScope
UpdateAndListen
(
154
Class* obj,
155
std::string_view name,
156
void
(Class::*func)(
const
dynamic_config::Snapshot& config)
157
) {
158
return
DoUpdateAndListen(
159
concurrent
::FunctionId(obj),
160
name,
161
[obj, func](
const
dynamic_config::Snapshot& config) { (obj->*func)(config); }
162
);
163
}
164
165
/// @brief Subscribes to dynamic-config updates with information about the
166
/// current and previous states.
167
///
168
/// Subscribes to dynamic-config updates using a member function, named
169
/// `OnConfigUpdate` by convention. Also constructs `dynamic_config::Diff`
170
/// object using `std::nullopt` and current config snapshot, then immediately
171
/// invokes the function with it (this invocation will be executed
172
/// synchronously).
173
///
174
/// Further updates are delivered after @ref utils::ResourceScopeStorage::AfterConstruction, including those updates
175
/// that arrived before it. Unsubscribe runs in @ref utils::ResourceScopeStorage::BeforeDestruction.
176
///
177
/// @note Callbacks occur in full accordance with
178
/// `components::DynamicConfigClientUpdater` options.
179
///
180
/// @warning In debug mode the last notification for any subscriber will be
181
/// called with `std::nullopt` and current config snapshot.
182
///
183
/// Example usage:
184
/// @snippet core/src/dynamic_config/config_test.cpp Custom subscription for dynamic config update
185
///
186
/// @param scopes storage that owns the subscription lifetime. In a component constructor pass `context.Scopes()`
187
/// or @ref components::GetResourceScopes.
188
/// @param obj the subscriber, which is the owner of the listener method, and
189
/// is also used as the unique identifier of the subscription
190
/// @param name the name of the subscriber, for diagnostic purposes
191
/// @param func the listener method, named `OnConfigUpdate` by convention.
192
///
193
/// @see based on concurrent::AsyncEventSource engine
194
///
195
/// @see dynamic_config::Diff
196
template
<
typename
Class>
197
void
UpdateAndListen
(
198
utils
::ResourceScopeStorage& scopes,
199
Class* obj,
200
std::string_view name,
201
void
(Class::*func)(
const
dynamic_config::Diff& diff)
202
) {
203
DoUpdateAndListen(scopes,
concurrent
::FunctionId(obj), name, [obj, func](
const
dynamic_config::Diff& diff) {
204
(obj->*func)(diff);
205
});
206
}
207
208
/// @overload
209
/// @deprecated Use the overloads that take @ref utils::ResourceScopeStorage.
210
///
211
/// Store the returned scope as a member and call `Unsubscribe` explicitly.
212
template
<
typename
Class>
213
concurrent
::AsyncEventSubscriberScope
UpdateAndListen
(
214
Class* obj,
215
std::string_view name,
216
void
(Class::*func)(
const
dynamic_config::Diff& diff)
217
) {
218
return
DoUpdateAndListen(
concurrent
::FunctionId(obj), name, [obj, func](
const
dynamic_config::Diff& diff) {
219
(obj->*func)(diff);
220
});
221
}
222
223
/// @brief Subscribes to updates of a subset of all configs.
224
///
225
/// Subscribes to dynamic-config updates using a member function, named
226
/// `OnConfigUpdate` by convention. The function will be invoked if at least
227
/// one of the configs has been changed since the previous invocation. So at
228
/// the first time immediately invokes the function with the current config
229
/// snapshot (this invocation will be executed synchronously).
230
///
231
/// Further updates are delivered after @ref utils::ResourceScopeStorage::AfterConstruction, including those updates
232
/// that arrived before it. Unsubscribe runs in @ref utils::ResourceScopeStorage::BeforeDestruction.
233
///
234
/// @note Callbacks occur only if one of the passed config is changed. This is
235
/// true under any components::DynamicConfigClientUpdater options.
236
///
237
/// @warning To use this function, configs must have the `operator==`.
238
///
239
/// @param scopes storage that owns the subscription lifetime. In a component constructor pass `context.Scopes()`
240
/// or @ref components::GetResourceScopes.
241
/// @param obj the subscriber, which is the owner of the listener method, and
242
/// is also used as the unique identifier of the subscription
243
/// @param name the name of the subscriber, for diagnostic purposes
244
/// @param func the listener method, named `OnConfigUpdate` by convention.
245
/// @param keys config objects, specializations of `dynamic_config::Key`.
246
///
247
/// @see based on concurrent::AsyncEventSource engine
248
template
<
typename
Class,
typename
... Keys>
249
void
UpdateAndListen
(
250
utils
::ResourceScopeStorage& scopes,
251
Class* obj,
252
std::string_view name,
253
void
(Class::*func)(
const
dynamic_config::Snapshot& config),
254
const
Keys&... keys
255
) {
256
auto
wrapper = [obj, func, &keys...](
const
Diff& diff) {
257
if
(!diff.HasConfigsChanged(keys...)) {
258
return
;
259
}
260
(obj->*func)(diff.current);
261
};
262
DoUpdateAndListen(scopes,
concurrent
::FunctionId(obj), name, std::move(wrapper));
263
}
264
265
/// @overload
266
/// @deprecated Use the overloads that take @ref utils::ResourceScopeStorage.
267
///
268
/// Store the returned scope as a member and call `Unsubscribe` explicitly.
269
template
<
typename
Class,
typename
... Keys>
270
concurrent
::AsyncEventSubscriberScope
UpdateAndListen
(
271
Class* obj,
272
std::string_view name,
273
void
(Class::*func)(
const
dynamic_config::Snapshot& config),
274
const
Keys&... keys
275
) {
276
auto
wrapper = [obj, func, &keys...](
const
Diff& diff) {
277
if
(!diff.HasConfigsChanged(keys...)) {
278
return
;
279
}
280
(obj->*func)(diff.current);
281
};
282
return
DoUpdateAndListen(
concurrent
::FunctionId(obj), name, std::move(wrapper));
283
}
284
285
SnapshotEventSource& GetEventChannel();
286
287
private
:
288
concurrent
::AsyncEventSubscriberScope DoUpdateAndListen(
289
concurrent
::FunctionId id,
290
std::string_view name,
291
SnapshotEventSource::Function&& func
292
);
293
294
concurrent
::AsyncEventSubscriberScope DoUpdateAndListen(
295
concurrent
::FunctionId id,
296
std::string_view name,
297
DiffEventSource::Function&& func
298
);
299
300
void
DoUpdateAndListen(
301
utils
::ResourceScopeStorage& scopes,
302
concurrent
::FunctionId id,
303
std::string_view name,
304
SnapshotEventSource::Function&& func
305
);
306
307
void
DoUpdateAndListen(
308
utils
::ResourceScopeStorage& scopes,
309
concurrent
::FunctionId id,
310
std::string_view name,
311
DiffEventSource::Function&& func
312
);
313
314
impl::StorageData* storage_;
315
};
316
317
}
// namespace dynamic_config
318
319
USERVER_NAMESPACE_END
userver
dynamic_config
source.hpp
Generated on
for userver by
Doxygen
1.17.0