userver: userver/dynamic_config/updater/component.hpp Source File
Loading...
Searching...
No Matches
component.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/dynamic_config/updater/component.hpp
4/// @brief @copybrief components::DynamicConfigClientUpdater
5
6#include <chrono>
7#include <functional>
8#include <optional>
9#include <string>
10#include <unordered_set>
11
12#include <userver/cache/cache_statistics.hpp>
13#include <userver/cache/caching_component_base.hpp>
14#include <userver/cache/update_type.hpp>
15#include <userver/components/component_fwd.hpp>
16#include <userver/concurrent/variable.hpp>
17#include <userver/dynamic_config/client/client.hpp>
18#include <userver/dynamic_config/snapshot.hpp>
19#include <userver/dynamic_config/storage/component.hpp>
20#include <userver/dynamic_config/updater/additional_keys_token.hpp>
21#include <userver/dynamic_config/updates_sink/component.hpp>
22#include <userver/engine/mutex.hpp>
23#include <userver/utils/impl/transparent_hash.hpp>
24
25USERVER_NAMESPACE_BEGIN
26
27namespace components {
28
29// clang-format off
30
31/// @ingroup userver_components
32///
33/// @brief Component that does a periodic update of runtime configs.
34///
35/// Note that the service with dynamic config update component and without
36/// configs cache requires successful update to start. See
37/// @ref dynamic_config_fallback for details and explanation.
38///
39/// ## Optional update event deduplication
40///
41/// Config update types to deduplicate. If enabled, JSON of the whole config is
42/// compared to the previous one; if same, no config update event is sent to the
43/// subscribers of dynamic_config::Source (`OnConfigUpdate` functions).
44///
45/// `deduplicate-update-types` static config option specifies the update types
46/// of the config cache, for which event deduplication should be performed.
47/// Possible values:
48/// - `none` (the default)
49/// - `only-full`
50/// - `only-incremental`
51/// - `full-and-incremental`
52///
53/// Full updates will always send an event unless deduplicated. Incremental
54/// updates may send an extra event for some config service implementations.
55///
56/// Note: This is not a silver bullet against extra events, because the events
57/// will be sent to every dynamic config subscriber if *any* part of the config
58/// has updated, not if the interesting part has updated.
59///
60/// ## Static options:
61/// Name | Description | Default value
62/// ---- | ----------- | -------------
63/// updates-sink | name of the component derived from components::DynamicConfigUpdatesSinkBase to be used for storing received updates | dynamic-config
64/// store-enabled | store the retrieved values into the updates sink determined by the `updates-sink` option | true
65/// load-only-my-values | request from the client only the values used by this service | true
66/// deduplicate-update-types | update types for best-effort update event deduplication, see above | `full-and-incremental`
67///
68/// See also the options for components::CachingComponentBase.
69///
70/// ## Static configuration example:
71///
72/// @snippet components/common_component_list_test.cpp Sample dynamic config client updater component config
73
74// clang-format on
75class DynamicConfigClientUpdater final
76 : public CachingComponentBase<dynamic_config::DocsMap> {
77 public:
78 /// @ingroup userver_component_names
79 /// @brief The default name of components::DynamicConfigClientUpdater
80 static constexpr std::string_view kName = "dynamic-config-client-updater";
81
82 DynamicConfigClientUpdater(const ComponentConfig&, const ComponentContext&);
83
84 ~DynamicConfigClientUpdater() override;
85
86 // After calling this method, `Get()` will return a dynamic_config containing
87 // the specified keys while the token that this method returned is alive.
88 dynamic_config::AdditionalKeysToken SetAdditionalKeys(
89 std::vector<std::string> keys);
90
91 static yaml_config::Schema GetStaticConfigSchema();
92
93 private:
94 void Update(cache::UpdateType update_type,
95 const std::chrono::system_clock::time_point& last_update,
96 const std::chrono::system_clock::time_point& now,
97 cache::UpdateStatisticsScope&) override;
98
99 void UpdateFull(const std::vector<std::string>& docs_map_keys,
100 cache::UpdateStatisticsScope&);
101
102 void UpdateIncremental(const std::vector<std::string>& docs_map_keys,
103 cache::UpdateStatisticsScope&);
104
105 dynamic_config::DocsMap MergeDocsMap(const dynamic_config::DocsMap& current,
106 dynamic_config::DocsMap&& update,
107 const std::vector<std::string>& removed);
108 void StoreIfEnabled();
109
110 using DocsMapKeys = utils::impl::TransparentSet<std::string>;
111 using AdditionalDocsMapKeys =
112 std::unordered_set<std::shared_ptr<std::vector<std::string>>>;
113
114 std::vector<std::string> GetDocsMapKeysToFetch(
115 AdditionalDocsMapKeys& additional_docs_map_keys);
116
117 void UpdateAdditionalKeys(const std::vector<std::string>& keys);
118
119 bool IsDuplicate(cache::UpdateType update_type,
120 const dynamic_config::DocsMap& new_value) const;
121
122 DynamicConfigUpdatesSinkBase& updates_sink_;
123 const bool load_only_my_values_;
124 const bool store_enabled_;
125 const std::optional<cache::AllowedUpdateTypes> deduplicate_update_types_;
126 dynamic_config::Client& config_client_;
127
128 bool is_empty_{true};
129 dynamic_config::Client::Timestamp server_timestamp_;
130 // for atomic updates of cached data
131 engine::Mutex update_config_mutex_;
132 DocsMapKeys docs_map_keys_;
133 concurrent::Variable<AdditionalDocsMapKeys> additional_docs_map_keys_;
134};
135
136template <>
137inline constexpr bool kHasValidate<DynamicConfigClientUpdater> = true;
138
139} // namespace components
140
141USERVER_NAMESPACE_END