7#ifndef BOOST_REDIS_HEALTH_CHECKER_HPP
8#define BOOST_REDIS_HEALTH_CHECKER_HPP
10#include <boost/redis/request.hpp>
11#include <boost/redis/response.hpp>
12#include <boost/redis/operation.hpp>
13#include <boost/redis/adapter/any_adapter.hpp>
14#include <boost/redis/config.hpp>
15#include <boost/redis/operation.hpp>
16#include <boost/asio/steady_timer.hpp>
17#include <boost/asio/compose.hpp>
18#include <boost/asio/consign.hpp>
19#include <boost/asio/coroutine.hpp>
20#include <boost/asio/post.hpp>
24namespace boost::redis::detail {
26template <
class HealthChecker,
class Connection,
class Logger>
29 HealthChecker* checker_ =
nullptr;
30 Connection* conn_ =
nullptr;
32 asio::coroutine coro_{};
35 void operator()(Self& self, system::error_code ec = {}, std::size_t = 0)
37 BOOST_ASIO_CORO_REENTER (coro_)
for (;;)
39 if (checker_->ping_interval_ == std::chrono::seconds::zero()) {
40 logger_.trace(
"ping_op (1): timeout disabled.");
42 asio::post(std::move(self));
47 if (checker_->checker_has_exited_) {
48 logger_.trace(
"ping_op (2): checker has exited.");
54 conn_->async_exec(checker_->req_, any_adapter(checker_->resp_), std::move(self));
56 logger_.trace(
"ping_op (3)", ec);
57 checker_->wait_timer_.cancel();
63 checker_->ping_timer_.expires_after(checker_->ping_interval_);
66 checker_->ping_timer_.async_wait(std::move(self));
68 logger_.trace(
"ping_op (4)", ec);
76template <
class HealthChecker,
class Connection,
class Logger>
77class check_timeout_op {
79 HealthChecker* checker_ =
nullptr;
80 Connection* conn_ =
nullptr;
82 asio::coroutine coro_{};
85 void operator()(Self& self, system::error_code ec = {})
87 BOOST_ASIO_CORO_REENTER (coro_)
for (;;)
89 if (checker_->ping_interval_ == std::chrono::seconds::zero()) {
90 logger_.trace(
"check_timeout_op (1): timeout disabled.");
92 asio::post(std::move(self));
97 checker_->wait_timer_.expires_after(2 * checker_->ping_interval_);
100 checker_->wait_timer_.async_wait(std::move(self));
102 logger_.trace(
"check_timeout_op (2)", ec);
107 if (checker_->resp_.has_error()) {
109 logger_.trace(
"check_timeout_op (3): Response error.");
114 if (checker_->resp_.value().empty()) {
115 logger_.trace(
"check_timeout_op (4): pong timeout.");
116 checker_->ping_timer_.cancel();
118 checker_->checker_has_exited_ =
true;
123 if (checker_->resp_.has_value()) {
124 checker_->resp_.value().clear();
130template <
class Executor>
131class health_checker {
134 asio::basic_waitable_timer<
135 std::chrono::steady_clock,
136 asio::wait_traits<std::chrono::steady_clock>,
140 health_checker(Executor ex)
144 req_.
push(
"PING",
"Boost.Redis");
147 void set_config(config
const& cfg)
150 req_.
push(
"PING", cfg.health_check_id);
151 ping_interval_ = cfg.health_check_interval;
156 ping_timer_.cancel();
157 wait_timer_.cancel();
160 template <
class Connection,
class Logger,
class CompletionToken>
161 auto async_ping(Connection& conn, Logger l, CompletionToken token)
163 return asio::async_compose
165 , void(system::error_code)
166 >(ping_op<health_checker, Connection, Logger>{
this, &conn, l}, token, conn, ping_timer_);
169 template <
class Connection,
class Logger,
class CompletionToken>
170 auto async_check_timeout(Connection& conn, Logger l, CompletionToken token)
172 checker_has_exited_ =
false;
173 return asio::async_compose
175 , void(system::error_code)
176 >(check_timeout_op<health_checker, Connection, Logger>{
this, &conn, l}, token, conn, wait_timer_);
180 template <
class,
class,
class>
friend class ping_op;
181 template <
class,
class,
class>
friend class check_timeout_op;
183 timer_type ping_timer_;
184 timer_type wait_timer_;
187 std::chrono::steady_clock::duration ping_interval_ = std::chrono::seconds{5};
188 bool checker_has_exited_ =
false;
void push(std::string_view cmd, Ts const &... args)
Appends a new command to the end of the request.
void clear()
Clears the request preserving allocated memory.
adapter::result< std::vector< resp3::node > > generic_response
A generic response to a request.
@ pong_timeout
Connect timeout.
@ run
Refers to connection::async_run operations.