userver: userver/ydb/dist_lock/component_base.hpp Source File
⚠️ This is the documentation for an old userver version. Click here to switch to the latest version.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
component_base.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/ydb/dist_lock/component_base.hpp
4/// @brief @copybrief ydb::DistLockComponentBase
5
6#include <optional>
7#include <string>
8
9#include <userver/components/loggable_component_base.hpp>
10#include <userver/utils/statistics/entry.hpp>
11#include <userver/ydb/dist_lock/worker.hpp>
12
13USERVER_NAMESPACE_BEGIN
14
15namespace testsuite {
16class TestsuiteTasks;
17} // namespace testsuite
18
19namespace ydb {
20
21// clang-format off
22
23/// @ingroup userver_components userver_base_classes
24///
25/// @brief Base class for YDB-based distlock worker components
26///
27/// A component that implements a distlock with lock in YDB. Inherit from
28/// DistLockComponentBase and implement DoWork(). Lock options are configured
29/// in static config.
30///
31/// The class must be used for infinite loop jobs.
32///
33/// ## Static configuration example:
34///
35/// @snippet ydb/functional_tests/basic/static_config.yaml sample-dist-lock
36///
37/// ## Static options:
38/// name | Description | Default value
39/// -------------- | ------------ | -------------
40/// semaphore-name | name of the semaphore within the coordination node | --
41/// database-settings.dbname | the key of the database within ydb component (NOT the actual database path) | --
42/// database-settings.coordination-node | name of the coordination node within the database | --
43/// initial-setup | if true, then create the coordination node and the semaphore unless they already exist | true
44/// task-processor | the name of the TaskProcessor for running DoWork | main-task-processor
45/// node-settings.session-grace-period | the time after which the lock will be given to another host after a network failure | 10s
46/// session-timeout | for how long we will try to restore session after a network failure before dropping it | 5s
47/// restart-session-delay | backoff before attempting to reconnect session after it returns "permanent failure" | 1s
48/// acquire-interval | backoff before repeating a failed Acquire call | 100ms
49/// restart-delay | backoff before calling DoWork again after it returns or throws | 100ms
50/// cancel-task-time-limit | time, within which a cancelled DoWork is expected to finish | 5s
51///
52/// @see @ref scripts/docs/en/userver/periodics.md
53
54// clang-format on
56 public:
57 DistLockComponentBase(const components::ComponentConfig&,
58 const components::ComponentContext&);
59 ~DistLockComponentBase() override;
60
61 /// @brief Checks if the the current service instance owns the lock.
62 ///
63 /// Useful for:
64 ///
65 /// 1. Writing metrics only on the primary (for the given distlock) host.
66 ///
67 /// 2. Running on-demand work, e.g. in handlers, only on the primary host.
68 /// The work must be short-lived (single requests with small timeout),
69 /// otherwise brain split
70 /// (where multiple hosts consider themselves primary) is possible.
71 bool OwnsLock() const noexcept;
72
73 static yaml_config::Schema GetStaticConfigSchema();
74
75 protected:
76 /// Override this function with anything that must be done under the lock.
77 ///
78 /// @note `DoWork` must honour task cancellation and stop ASAP when
79 /// it is cancelled, otherwise brain split is possible (IOW, two different
80 /// users do work assuming both of them hold the lock, which is not true).
81 ///
82 /// @note When DoWork exits for any reason, the lock is dropped, then after
83 /// `restart-delay` the lock is attempted to be re-acquired (but by that time
84 /// another host likely acquires the lock).
85 ///
86 /// ## Example implementation
87 ///
88 /// @snippet ydb/functional_tests/basic/ydb_service.cpp DoWork
89 virtual void DoWork() = 0;
90
91 /// Override this function to provide a custom testsuite handler, e.g. one
92 /// that does not contain a "while not cancelled" loop.
93 /// Calls `DoWork` by default.
94 ///
95 /// In testsuite runs, the normal DoWork execution disabled by default.
96 /// There is an API to call DoWorkTestsuite from testsuite, imitating waiting
97 /// until DoWork runs:
98 ///
99 /// @snippet ydb/functional_tests/basic/tests/test_distlock.py run
100 virtual void DoWorkTestsuite() { DoWork(); }
101
102 /// Must be called at the end of the constructor of the derived component.
103 void Start();
104
105 /// Must be called in the destructor of the derived component.
106 void Stop() noexcept;
107
108 private:
109 testsuite::TestsuiteTasks& testsuite_tasks_;
110 const std::string testsuite_task_name_;
111
112 // Worker contains a task that may refer to other fields, so it must be right
113 // before subscriptions. Add new fields above this comment.
114 std::optional<DistLockedWorker> worker_;
115
116 // Subscriptions must be the last fields.
117 utils::statistics::Entry statistics_holder_;
118};
119
120} // namespace ydb
121
122USERVER_NAMESPACE_END