OZO 「お象」
Boost.Asio and libpq based asynchronous PostgreSQL unofficial header-only C++17 client library.
retry.h
1 #pragma once
2 
3 #include <ozo/failover/strategy.h>
4 #include <ozo/core/options.h>
5 
12 namespace ozo::failover {
13 
14 namespace detail {
15 
16 template <typename TimeConstraint, typename Now = decltype(time_traits::now)>
17 inline auto get_try_time_constraint(TimeConstraint t, int n_tries, [[maybe_unused]] Now now = time_traits::now) {
18  if constexpr (t == none) {
19  return none;
20  } else if constexpr (std::is_same_v<TimeConstraint, time_traits::time_point>) {
21  return n_tries > 0 ? time_left(t, now()) / n_tries : time_traits::duration{0};
22  } else {
23  return n_tries > 0 ? t / n_tries : time_traits::duration{0};
24  }
25 }
26 
27 template <typename ...ErrorConditions>
28 constexpr auto make_errcs_tuple(ErrorConditions ...errcs) {
29  return hana::make_tuple(errcs...);
30 }
31 
32 } // namespace detail
33 
40 struct retry_options {
41  class on_retry_tag;
42  class close_connection_tag;
43  class tries_tag;
44  class conditions_tag;
45 
46  constexpr static option<on_retry_tag> on_retry{};
48  constexpr static option<tries_tag> tries{};
49  constexpr static option<conditions_tag> conditions{};
50 };
51 
62 template <typename Options, typename Context>
63 class basic_try {
64  Context ctx_;
65  Options options_;
66  using op = retry_options;
67 
68 public:
75  constexpr basic_try(Options options, Context ctx)
76  : ctx_(std::move(ctx)), options_(std::move(options)) {
77  static_assert(decltype(hana::is_a<hana::map_tag>(options))::value, "Options should be boost::hana::map");
78  }
79  constexpr basic_try(const basic_try&) = delete;
80  constexpr basic_try(basic_try&&) = default;
81  constexpr basic_try& operator = (const basic_try&) = delete;
82  constexpr basic_try& operator = (basic_try&&) = default;
83 
84  constexpr const Options& options() const { return options_;}
85  constexpr Options& options() { return options_;}
86 
93  auto get_context() const {
94  return hana::concat(
95  hana::make_tuple(ozo::unwrap(ctx_).provider, time_constraint()),
96  ozo::unwrap(ctx_).args
97  );
98  }
99 
112  template <typename Connection>
113  std::optional<basic_try> get_next_try(ozo::error_code ec, Connection&& conn) {
114  auto guard = defer_close_connection(get_option(options(), op::close_connection, true) ? std::addressof(conn) : nullptr);
115 
116  std::optional<basic_try> retval;
117  adjust_tries_remain();
118  if (can_retry(ec)) {
119  get_option(options(), op::on_retry, [](auto&&...){})(ec, conn);
120  retval.emplace(basic_try{std::move(options_), std::move(ctx_)});
121  }
122 
123  return retval;
124  }
125 
131  constexpr int tries_remain() const { return get_option(options(), op::tries);}
132 
139  constexpr decltype(auto) get_conditions() const {
140  return get_option(options(), op::conditions, no_conditions_);
141  }
142 
143  auto time_constraint() const {
144  return detail::get_try_time_constraint(ozo::unwrap(ctx_).time_constraint, tries_remain());
145  }
146 
147 private:
148  void adjust_tries_remain() {
149  options_[op::tries] = std::max(0, tries_remain() - 1);
150  }
151 
152  bool can_retry([[maybe_unused]] error_code ec) const {
153  if(tries_remain() < 1) {
154  return false;
155  }
156 
157  if constexpr (decltype(hana::is_empty(get_conditions()))::value) {
158  return true;
159  } else {
160  return errc::match_code(get_conditions(), ec);
161  }
162  }
163  constexpr static const auto no_conditions_ = hana::make_tuple();
164 };
165 
166 
175 template <typename Options = decltype(hana::make_map())>
176 class retry_strategy : public ozo::options_factory_base<retry_strategy<Options>, Options> {
177  using op = retry_options;
178 
179  friend class ozo::options_factory_base<retry_strategy<Options>, Options>;
181 
182  template <typename OtherOptions>
183  constexpr static auto rebind_options(OtherOptions&& options) {
184  return retry_strategy<std::decay_t<OtherOptions>>(std::forward<OtherOptions>(options));
185  }
186 
187 public:
193  constexpr retry_strategy(Options options = Options{}) : base(std::move(options)) {
194  static_assert(decltype(hana::is_a<hana::map_tag>(options))::value, "Options should be boost::hana::map");
195  }
196 
207  template <typename Operation, typename Allocator, typename ConnectionProvider,
208  typename TimeConstraint, typename ...Args>
209  auto get_first_try(const Operation&, const Allocator&,
210  ConnectionProvider&& provider, TimeConstraint t, Args&& ...args) const {
211 
212  static_assert(decltype(this->has(op::tries))::value, "number of tries should be specified");
213 
214  return basic_try {
215  this->options(),
217  std::forward<ConnectionProvider>(provider),
218  ozo::deadline(t),
219  std::forward<Args>(args)...
220  }
221  };
222  }
223 
255  constexpr decltype(auto) tries(int n) const & { return this->set(op::tries, n);}
256  constexpr decltype(auto) tries(int n) && { return std::move(*this).set(op::tries, n);}
257 
263  constexpr int get_tries() const { return this->get(op::tries); }
264 
270  constexpr auto get_conditions() const { return this->get(op::conditions); }
271 
278  constexpr decltype(auto) operator * (int n) const & { return tries(n); }
279  constexpr decltype(auto) operator * (int n) && { return std::move(*this).tries(n); }
280 };
281 
282 template <typename ...Ts>
283 constexpr decltype(auto) operator * (int n, const retry_strategy<Ts...>& rs) { return rs * n;}
284 template <typename ...Ts>
285 constexpr decltype(auto) operator * (int n, retry_strategy<Ts...>&& rs) { return std::move(rs) * n;}
286 
307 template <typename ...ErrorConditions>
308 constexpr auto retry(ErrorConditions ...ec) {
309  if constexpr (sizeof...(ec) != 0) {
310  return retry_strategy{}.set(retry_options::conditions=hana::make_tuple(ec...));
311  } else {
312  return retry_strategy{};
313  }
314 }
315 
316 } // namespace ozo::failover
317 
318 namespace ozo {
319 
320 template <typename ...Ts, typename Op>
321 struct construct_initiator_impl<failover::retry_strategy<Ts...>, Op>
322 : failover::construct_initiator_impl {};
323 
324 } // namespace ozo
ozo::failover::retry_strategy::get_first_try
auto get_first_try(const Operation &, const Allocator &, ConnectionProvider &&provider, TimeConstraint t, Args &&...args) const
Get the first try object.
Definition: retry.h:209
ozo::unwrap
constexpr decltype(auto) unwrap(T &&v) noexcept(noexcept(unwrap_impl< std::decay_t< T >>::apply(std::forward< T >(v))))
Unwraps argument underlying value or forwards the argument.
Definition: unwrap.h:57
ozo::error_code
boost::system::error_code error_code
Error code representation of the library.
Definition: error.h:38
ozo::failover::basic_context
Basic operation context.
Definition: strategy.h:150
ozo::deadline
constexpr time_traits::time_point deadline(time_traits::time_point t) noexcept
Dealdine calculation.
Definition: deadline.h:16
ozo::failover::retry_strategy::tries
constexpr decltype(auto) tries(int n) const &
Specify number of tries.
Definition: retry.h:255
ozo::time_traits::now
static time_point now() noexcept(noexcept(std::chrono::steady_clock::now()))
Definition: time_traits.h:20
ozo::failover::retry_options::close_connection
constexpr static option< close_connection_tag > close_connection
Set close connection policy on retry, possible values true(default), false.
Definition: retry.h:47
ozo::failover::retry_options
Options for retry.
Definition: retry.h:40
ozo::failover::retry_strategy::get_conditions
constexpr auto get_conditions() const
Retry error conditions of the strategy.
Definition: retry.h:270
ozo::defer_close_connection
auto defer_close_connection(Connection *conn)
Close connection to the database when leaving the scope.
Definition: connection.h:891
ConnectionProvider
Connection provider concept
ozo::none
constexpr auto none
None object.
Definition: none.h:27
ozo::options_factory_base< retry_strategy< decltype(hana::make_map()) >, decltype(hana::make_map()) >::get
constexpr decltype(auto) get(ozo::option< Key > op) const
Definition: options.h:243
ozo::failover::retry_options::tries
constexpr static option< tries_tag > tries
Set number of tries, see ozo::retry_strategy::tries() for more information.
Definition: retry.h:48
ozo::failover::retry_strategy::get_tries
constexpr int get_tries() const
Number of maximum tries count are setted with ozo::retry_strategy::tries()
Definition: retry.h:263
ozo::failover::retry
constexpr auto retry(ErrorConditions ...ec)
Definition: retry.h:308
ozo::failover::retry_options::on_retry
constexpr static option< on_retry_tag > on_retry
Set handler for retry event, may be useful for logging.
Definition: retry.h:46
ozo::value
Database request result value proxy.
Definition: result.h:25
ozo::failover::retry_strategy::retry_strategy
constexpr retry_strategy(Options options=Options{})
Construct a new retry strategy object.
Definition: retry.h:193
ozo::failover::basic_try::basic_try
constexpr basic_try(Options options, Context ctx)
Construct a new basic try object.
Definition: retry.h:75
ozo::failover::retry_options::conditions
constexpr static option< conditions_tag > conditions
Set error conditions to retry.
Definition: retry.h:49
ozo::failover::basic_try::get_next_try
std::optional< basic_try > get_next_try(ozo::error_code ec, Connection &&conn)
Get the next try.
Definition: retry.h:113
ozo::failover::basic_try::get_context
auto get_context() const
Get the operation context.
Definition: retry.h:93
ozo::failover::basic_try
Operation try representation.
Definition: retry.h:63
ozo::failover::basic_try::get_conditions
constexpr decltype(auto) get_conditions() const
Retry conditions for the try.
Definition: retry.h:139
ozo::options_factory_base
Base class for options factories.
Definition: options.h:121
ozo::time_traits::duration
std::chrono::steady_clock::duration duration
Time duration type of the library.
Definition: time_traits.h:13
ozo::option< on_retry_tag >
ozo::get_option
constexpr decltype(auto) get_option(Map &&map, ozo::option< Key > op)
Get the option object from Hana.Map.
Definition: options.h:52
ozo::time_left
constexpr time_traits::duration time_left(time_traits::time_point t, time_traits::time_point now) noexcept
Time left to deadline.
Definition: deadline.h:77
ozo::failover::basic_try::tries_remain
constexpr int tries_remain() const
Number of tries remains.
Definition: retry.h:131
Connection
Database connection concept.
ozo::failover::retry_strategy
Retry strategy.
Definition: retry.h:176
ozo::options_factory_base< retry_strategy< decltype(hana::make_map()) >, decltype(hana::make_map()) >::options
constexpr const decltype(hana::make_map()) & options() const &
Definition: options.h:250
ozo::options_factory_base< retry_strategy< decltype(hana::make_map()) >, decltype(hana::make_map()) >::set
constexpr decltype(auto) set(decltype(hana::make_map()) &&...options) &&
ozo::options_factory_base< retry_strategy< decltype(hana::make_map()) >, decltype(hana::make_map()) >::has
constexpr auto has(ozo::option< Key > op) const
Definition: options.h:232