userver: userver/storages/mongo/dist_lock_component_base.hpp Source File
Loading...
Searching...
No Matches
dist_lock_component_base.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/storages/mongo/dist_lock_component_base.hpp
4/// @brief @copybrief storages::mongo::DistLockComponentBase
5
6#include <userver/components/component_base.hpp>
7#include <userver/dist_lock/dist_locked_worker.hpp>
8#include <userver/storages/mongo/collection.hpp>
9#include <userver/storages/mongo/dist_lock_strategy.hpp>
10#include <userver/utils/statistics/entry.hpp>
11
12USERVER_NAMESPACE_BEGIN
13
14namespace storages::mongo {
15
16// clang-format off
17
18/// @ingroup userver_components userver_base_classes
19///
20/// @brief Base class for mongo-based distlock worker components
21///
22/// A component that implements a distlock with lock in Mongo. Inherit from
23/// DistLockComponentBase and implement DoWork(). Lock options are configured
24/// in static config.
25///
26/// Mongo might not perform well on a high load, so you might want to use
27/// postgres-based distlock storages::postgres::DistLockComponentBase instead.
28/// @see storages::postgres::DistLockComponentBase
29///
30/// ## Cancellation checks
31/// Functions engine::current_task::ShouldCancel(),
32/// engine::InterruptibleSleepFor(), engine::InterruptibleSleepUntil() and
33/// engine::current_task::CancellationPoint() check for task cancellation.
34/// Overridden DistLockComponentBase::DoWork must use the above functions to
35/// honour task cancellation and stop ASAP when
36/// it is cancelled.
37///
38/// ## Static configuration example:
39///
40/// ```yaml
41/// example-distlock:
42/// lockname: master
43/// mongo-timeout: 1s
44/// lock-ttl: 10s
45/// ```
46///
47/// ## Static options:
48/// name | Description | Default value
49/// -------------- | ------------ | -------------
50/// lockname | name of the lock | --
51/// lock-ttl | TTL of the lock; must be at least as long as the duration between subsequent cancellation checks, otherwise brain split is possible | --
52/// mongo-timeout | timeout, must be less than lock-ttl / 2 | --
53/// restart-delay | how much time to wait after failed task restart | 100ms
54/// task-processor | the name of the TaskProcessor for running DoWork | main-task-processor
55/// testsuite-support | Enable testsuite support | false
56///
57/// @see @ref scripts/docs/en/userver/periodics.md
58
59// clang-format on
60
62public:
63 DistLockComponentBase(
64 const components::ComponentConfig&,
65 const components::ComponentContext&,
66 storages::mongo::Collection
67 );
68
69 ~DistLockComponentBase() override;
70
71 dist_lock::DistLockedWorker& GetWorker();
72
73 bool OwnsLock() const noexcept;
74
75 static yaml_config::Schema GetStaticConfigSchema();
76
77protected:
78 /// Override this function with anything that must be done under the mongo
79 /// lock.
80 ///
81 /// ## Example implementation
82 ///
83 /// @code
84 /// void MyDistLockComponent::DoWork()
85 /// {
86 /// while (!engine::ShouldCancel())
87 /// {
88 /// // Start a new trace_id
89 /// auto span = tracing::Span::MakeRootSpan("my-dist-lock");
90 ///
91 /// // If Foo() or other function in DoWork() throws an exception,
92 /// // DoWork() will be restarted in `restart-delay` seconds.
93 /// Foo();
94 ///
95 /// // Check for cancellation after cpu-intensive Foo().
96 /// // You must check for cancellation at least every `lock-ttl`
97 /// // seconds to have time to notice lock prolongation failure.
98 /// if (engine::ShouldCancel()) break;
99 ///
100 /// Bar();
101 /// }
102 /// }
103 /// @endcode
104 ///
105 /// @note `DoWork` must honour task cancellation and stop ASAP when
106 /// it is cancelled, otherwise brain split is possible (IOW, two different
107 /// users do work assuming both of them hold the lock, which is not true).
108 virtual void DoWork() = 0;
109
110 /// Override this function to provide custom testsuite handler.
111 virtual void DoWorkTestsuite() { DoWork(); }
112
113 /// Must be called in constructor
114 void Start();
115
116 /// Must be called in destructor
117 void Stop();
118
119private:
120 std::unique_ptr<dist_lock::DistLockedWorker> worker_;
121 bool testsuite_enabled_{false};
122
123 // Subscriptions must be the last fields.
124 utils::statistics::Entry statistics_holder_;
125};
126
127} // namespace storages::mongo
128
129USERVER_NAMESPACE_END