userver: userver/dist_lock/dist_locked_worker.hpp Source File
Loading...
Searching...
No Matches
dist_locked_worker.hpp
1#pragma once
2
3#include <chrono>
4#include <functional>
5#include <memory>
6#include <optional>
7#include <string>
8
9#include <userver/dist_lock/dist_lock_settings.hpp>
10#include <userver/dist_lock/dist_lock_strategy.hpp>
11#include <userver/dist_lock/statistics.hpp>
12#include <userver/engine/mutex.hpp>
13#include <userver/engine/task/task_with_result.hpp>
14#include <userver/logging/level.hpp>
15
16USERVER_NAMESPACE_BEGIN
17
18namespace dist_lock {
19namespace impl {
20
21class Locker;
22
23} // namespace impl
24
25/// A high-level primitive that perpetually tries to acquire a distributed lock
26/// and runs user callback in a separate task while the lock is held.
27/// Cancels the task when the lock is lost.
28class DistLockedWorker final {
29public:
30 using WorkerFunc = std::function<void()>;
31
32 /// Creates a DistLockedWorker.
33 /// @param name name of the worker
34 /// @param worker_func a callback that's started each time we acquire the lock
35 /// and is cancelled when the lock is lost.
36 /// @param settings distributed lock settings
37 /// @param strategy distributed locking strategy
38 /// @param task_processor TaskProcessor for running `worker_func`,
39 /// using current TaskProcessor if `nullptr`
40 /// @param locker_log_level Log level for Locker (default is info)
41 /// @note `worker_func` must honour task cancellation and stop ASAP when
42 /// it is cancelled, otherwise brain split is possible (IOW, two different
43 /// users do work assuming both of them hold the lock, which is not true).
45 std::string name,
46 WorkerFunc worker_func,
47 std::shared_ptr<DistLockStrategyBase> strategy,
48 const DistLockSettings& settings = {},
49 engine::TaskProcessor* task_processor = nullptr,
50 logging::Level locker_log_level = logging::Level::kInfo
51 );
52
53 ~DistLockedWorker();
54
55 /// Name of the worker.
56 const std::string& Name() const;
57
58 /// Retrieves settings in a thread-safe way.
60
61 /// Update settings in a thread-safe way.
63
64 /// Starts acquiring the lock. Please note that it's possible that the lock is
65 /// acquired and the WorkerFunc is entered *before* Start() returns.
66 /// @see DistLockedTask::DistLockedTask
67 void Start();
68
69 /// Stops acquiring the lock. It is guaranteed that the lock is not held after
70 /// Stop() return and WorkerFunc is stopped (if was started).
71 void Stop();
72
73 /// Run task once acquiring the lock.
74 /// @throws std::exception rethrows exception from `worker_func`.
75 void RunOnce();
76
77 /// @returns whether the DistLockedTask is started.
78 bool IsRunning() const;
79
80 /// @returns is current worker owns the lock
81 bool OwnsLock() const noexcept;
82
83 /// Returns for how long the lock is held (if held at all). Returned value
84 /// may be less than the real duration.
85 std::optional<std::chrono::steady_clock::duration> GetLockedDuration() const;
86
87 /// Returns lock acquisition statistics.
88 const Statistics& GetStatistics() const;
89
90private:
91 engine::TaskProcessor& GetTaskProcessor() const noexcept;
92
93 std::shared_ptr<impl::Locker> locker_ptr_;
94
95 mutable engine::Mutex locker_task_mutex_;
96 engine::TaskWithResult<void> locker_task_;
97
98 engine::TaskProcessor* const task_processor_;
99};
100
101void DumpMetric(utils::statistics::Writer& writer, const DistLockedWorker& worker);
102
103} // namespace dist_lock
104
105USERVER_NAMESPACE_END