7#ifndef BOOST_REDIS_RUNNER_HPP
8#define BOOST_REDIS_RUNNER_HPP
10#include <boost/redis/detail/health_checker.hpp>
11#include <boost/redis/config.hpp>
12#include <boost/redis/response.hpp>
13#include <boost/redis/detail/helper.hpp>
14#include <boost/redis/error.hpp>
15#include <boost/redis/logger.hpp>
16#include <boost/redis/operation.hpp>
17#include <boost/redis/detail/connector.hpp>
18#include <boost/redis/detail/resolver.hpp>
19#include <boost/redis/detail/handshaker.hpp>
20#include <boost/asio/compose.hpp>
21#include <boost/asio/coroutine.hpp>
22#include <boost/asio/experimental/parallel_group.hpp>
23#include <boost/asio/ip/tcp.hpp>
24#include <boost/asio/steady_timer.hpp>
25#include <boost/asio/prepend.hpp>
30namespace boost::redis::detail
33void push_hello(config
const& cfg, request& req);
35template <
class Runner,
class Connection,
class Logger>
37 Runner* runner_ =
nullptr;
38 Connection* conn_ =
nullptr;
40 asio::coroutine coro_{};
43 void operator()(Self& self, system::error_code ec = {}, std::size_t = 0)
45 BOOST_ASIO_CORO_REENTER (coro_)
50 conn_->async_exec(runner_->hello_req_, runner_->hello_resp_, std::move(self));
51 logger_.on_hello(ec, runner_->hello_resp_);
53 if (ec || runner_->has_error_in_response() || is_cancelled(self)) {
54 logger_.trace(
"hello-op: error/canceled. Exiting ...");
56 self.complete(!!ec ? ec : asio::error::operation_aborted);
65template <
class Runner,
class Connection,
class Logger>
68 Runner* runner_ =
nullptr;
69 Connection* conn_ =
nullptr;
71 asio::coroutine coro_{};
74 runner_op(Runner* runner, Connection* conn, Logger l)
81 void operator()( Self& self
82 , std::array<std::size_t, 3> order = {}
83 , system::error_code ec0 = {}
84 , system::error_code ec1 = {}
85 , system::error_code ec2 = {}
88 BOOST_ASIO_CORO_REENTER (coro_)
91 runner_->resv_.async_resolve(
92 asio::prepend(std::move(self), std::array<std::size_t, 3> {}));
94 logger_.on_resolve(ec0, runner_->resv_.results());
96 if (ec0 || redis::detail::is_cancelled(self)) {
97 self.complete(!!ec0 ? ec0 : asio::error::operation_aborted);
101 BOOST_ASIO_CORO_YIELD
102 runner_->ctor_.async_connect(
103 conn_->next_layer().next_layer(),
104 runner_->resv_.results(),
105 asio::prepend(std::move(self), std::array<std::size_t, 3> {}));
107 logger_.on_connect(ec0, runner_->ctor_.endpoint());
109 if (ec0 || redis::detail::is_cancelled(self)) {
110 self.complete(!!ec0 ? ec0 : asio::error::operation_aborted);
114 if (conn_->use_ssl()) {
115 BOOST_ASIO_CORO_YIELD
116 runner_->hsher_.async_handshake(
118 asio::prepend(std::move(self),
119 std::array<std::size_t, 3> {}));
121 logger_.on_ssl_handshake(ec0);
122 if (ec0 || redis::detail::is_cancelled(self)) {
123 self.complete(!!ec0 ? ec0 : asio::error::operation_aborted);
131 BOOST_ASIO_CORO_YIELD
132 asio::experimental::make_parallel_group(
133 [
this](
auto token) {
return runner_->async_hello(*conn_, logger_, token); },
134 [
this](
auto token) {
return runner_->health_checker_.async_check_health(*conn_, logger_, token); },
135 [
this](
auto token) {
return conn_->async_run_lean(runner_->cfg_, logger_, token); }
137 asio::experimental::wait_for_one_error(),
140 logger_.on_runner(ec0, ec1, ec2);
142 if (is_cancelled(self)) {
143 self.complete(asio::error::operation_aborted);
147 if (order[0] == 0 && !!ec0) {
162template <
class Executor>
165 runner(Executor ex, config cfg)
168 , health_checker_{ex}
176 health_checker_.cancel(op);
180 void set_config(config
const& cfg)
183 resv_.set_config(cfg);
184 ctor_.set_config(cfg);
185 hsher_.set_config(cfg);
186 health_checker_.set_config(cfg);
189 template <
class Connection,
class Logger,
class CompletionToken>
190 auto async_run(Connection& conn, Logger l, CompletionToken token)
192 return asio::async_compose
194 , void(system::error_code)
195 >(runner_op<runner, Connection, Logger>{
this, &conn, l}, token, conn);
198 config
const& get_config() const noexcept {
return cfg_;}
201 using resolver_type = resolver<Executor>;
202 using handshaker_type = detail::handshaker<Executor>;
203 using health_checker_type = health_checker<Executor>;
205 template <
class,
class,
class>
friend class runner_op;
206 template <
class,
class,
class>
friend struct hello_op;
208 template <
class Connection,
class Logger,
class CompletionToken>
209 auto async_hello(Connection& conn, Logger l, CompletionToken token)
211 return asio::async_compose
213 , void(system::error_code)
214 >(hello_op<runner, Connection, Logger>{
this, &conn, l}, token, conn);
220 if (hello_resp_.has_value())
221 hello_resp_.value().clear();
222 push_hello(cfg_, hello_req_);
225 bool has_error_in_response() const noexcept
227 if (!hello_resp_.has_value())
230 auto f = [](
auto const& e)
232 switch (e.data_type) {
235 default:
return false;
239 return std::any_of(std::cbegin(hello_resp_.value()), std::cend(hello_resp_.value()), f);
244 handshaker_type hsher_;
245 health_checker_type health_checker_;
adapter::result< std::vector< resp3::node > > generic_response
A generic response to a request.
operation
Connection operations that can be cancelled.
@ pong_timeout
Connect timeout.
@ run
Refers to connection::async_run operations.