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