userver: userver/ydb/dist_lock/component_base.hpp Source File
Loading...
Searching...
No Matches
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