ORE Studio 0.0.4
Loading...
Searching...
No Matches
retry.hpp
1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 *
3 * Copyright (C) 2026 Marco Craveiro <marco.craveiro@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it under
6 * the terms of the GNU General Public License as published by the Free Software
7 * Foundation; either version 3 of the License, or (at your option) any later
8 * version.
9 *
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
13 * details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc., 51
17 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 *
19 */
20#ifndef ORES_NATS_SERVICE_RETRY_HPP
21#define ORES_NATS_SERVICE_RETRY_HPP
22
23#include <chrono>
24#include <string_view>
25#include <boost/asio/awaitable.hpp>
26#include <boost/system/system_error.hpp>
27#include <boost/asio/steady_timer.hpp>
28#include <boost/asio/this_coro.hpp>
29#include <boost/asio/use_awaitable.hpp>
30#include "ores.logging/make_logger.hpp"
31
32namespace ores::nats::service {
33
47template<typename Fn>
48boost::asio::awaitable<void>
49retry_with_backoff(Fn&& fn,
50 std::string_view operation_name,
51 std::chrono::milliseconds initial_delay = std::chrono::seconds(1),
52 std::chrono::milliseconds max_delay = std::chrono::seconds(30),
53 int max_retries = -1) {
54
55 using namespace ores::logging;
56 static const std::string_view logger_name = "ores.nats.service.retry";
57 static auto& lg = []() -> auto& {
58 static auto instance = make_logger(logger_name);
59 return instance;
60 }();
61
62 auto delay = initial_delay;
63 for (int attempt = 0; ; ++attempt) {
64 bool failed = false;
65 try {
66 co_await fn();
67 co_return;
68 } catch (const boost::system::system_error&) {
69 throw; // propagate cancellation and other system errors unmodified
70 } catch (const std::exception& e) {
71 if (max_retries >= 0 && attempt >= max_retries)
72 throw;
73
74 BOOST_LOG_SEV(lg, warn)
75 << operation_name << " failed (attempt " << (attempt + 1)
76 << "): " << e.what()
77 << ". Retrying in " << delay.count() << " ms.";
78 failed = true;
79 }
80
81 // co_await is not allowed inside a catch handler — do the sleep here.
82 if (failed) {
83 const auto ex = co_await boost::asio::this_coro::executor;
84 boost::asio::steady_timer timer(ex, delay);
85 co_await timer.async_wait(boost::asio::use_awaitable);
86 delay = std::min(delay * 2, max_delay);
87 }
88 }
89}
90
91} // namespace ores::nats::service
92
93#endif
Implements logging infrastructure for ORE Studio.
Definition boost_severity.hpp:28