Monitoring System 0.1.0
System resource monitoring with pluggable collectors and alerting
Loading...
Searching...
No Matches
retry_policy.h
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2021-2025, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
11#pragma once
12
13#include <algorithm>
14#include <chrono>
15#include <cmath>
16#include <functional>
17#include <string>
18#include <thread>
19
21
22namespace kcenon::monitoring {
23
33
38 size_t total_executions = 0;
41 size_t total_retries = 0;
42
43 void reset() {
47 total_retries = 0;
48 }
49};
50
55 size_t max_attempts = 3;
57 std::chrono::milliseconds initial_delay = std::chrono::milliseconds(1000);
58 std::chrono::milliseconds max_delay = std::chrono::milliseconds(30000);
59 double backoff_multiplier = 2.0;
60 std::function<bool(const error_info&)> should_retry = nullptr;
61
66 bool validate() const {
67 if (max_attempts == 0) {
68 return false;
69 }
70 if (backoff_multiplier < 1.0) {
71 return false;
72 }
73 return true;
74 }
75};
76
84 size_t max_attempts = 3,
85 std::chrono::milliseconds initial_delay = std::chrono::milliseconds(1000)) {
86 retry_config config;
87 config.max_attempts = max_attempts;
89 config.initial_delay = initial_delay;
90 config.backoff_multiplier = 2.0;
91 return config;
92}
93
101 size_t max_attempts = 3,
102 std::chrono::milliseconds delay = std::chrono::milliseconds(1000)) {
103 retry_config config;
104 config.max_attempts = max_attempts;
106 config.initial_delay = delay;
107 return config;
108}
109
117 size_t max_attempts = 3,
118 std::chrono::milliseconds initial_delay = std::chrono::milliseconds(1000)) {
119 retry_config config;
120 config.max_attempts = max_attempts;
122 config.initial_delay = initial_delay;
123 return config;
124}
125
133template<typename T>
135public:
137
138 retry_executor() : name_("default"), config_() {}
139
140 explicit retry_executor(const std::string& name)
141 : name_(name), config_() {}
142
143 explicit retry_executor(const std::string& name, const config& cfg)
144 : name_(name), config_(cfg) {}
145
153 template<typename Func>
154 common::Result<T> execute(Func&& func) {
156
157 common::Result<T> last_result = common::Result<T>::err(error_info(monitoring_error_code::operation_failed, "No attempts made").to_common_error());
158
159 for (size_t attempt = 0; attempt < config_.max_attempts; ++attempt) {
160 if (attempt > 0) {
162 auto delay = calculate_delay(attempt);
163 std::this_thread::sleep_for(delay);
164 }
165
166 last_result = func();
167
168 if (last_result.is_ok()) {
170 return last_result;
171 }
172
173 if (config_.should_retry) {
174 auto err_info = error_info::from_common_error(last_result.error());
175 if (!config_.should_retry(err_info)) {
177 return last_result;
178 }
179 }
180 }
181
183 return last_result;
184 }
185
190 return metrics_;
191 }
192
197 metrics_.reset();
198 }
199
203 const std::string& get_name() const {
204 return name_;
205 }
206
207private:
213 std::chrono::milliseconds calculate_delay(size_t attempt) const {
214 std::chrono::milliseconds delay;
215
216 switch (config_.strategy) {
219 break;
220
222 auto multiplier = std::pow(config_.backoff_multiplier, static_cast<double>(attempt - 1));
223 auto delay_ms = static_cast<long long>(config_.initial_delay.count() * multiplier);
224 delay = std::chrono::milliseconds(delay_ms);
225 break;
226 }
227
229 delay = config_.initial_delay * attempt;
230 break;
231
234 break;
235 }
236
237 default:
239 break;
240 }
241
242 return std::min(delay, config_.max_delay);
243 }
244
250 static size_t fibonacci(size_t n) {
251 if (n <= 1) return 1;
252
253 size_t prev = 1;
254 size_t curr = 1;
255
256 for (size_t i = 2; i <= n; ++i) {
257 size_t next = prev + curr;
258 prev = curr;
259 curr = next;
260 }
261
262 return curr;
263 }
264
265 std::string name_;
268};
269
274public:
276
278 explicit retry_policy(const config& cfg) : config_(cfg) {}
279
280 template<typename Func>
281 auto execute(Func&& func) -> decltype(func()) {
282 return func();
283 }
284
285private:
287};
288
289} // namespace kcenon::monitoring
Retry executor template class.
retry_executor(const std::string &name, const config &cfg)
const std::string & get_name() const
Get executor name.
void reset_metrics()
Reset metrics.
retry_metrics get_metrics() const
Get retry metrics.
retry_executor(const std::string &name)
common::Result< T > execute(Func &&func)
Execute a function with retry logic.
std::chrono::milliseconds calculate_delay(size_t attempt) const
Calculate delay for the current attempt.
static size_t fibonacci(size_t n)
Calculate Fibonacci number.
Basic retry policy implementation (backward compatibility)
auto execute(Func &&func) -> decltype(func())
@ delay
Delay requests until resources are available.
retry_strategy
Retry strategies.
retry_config create_fixed_delay_config(size_t max_attempts=3, std::chrono::milliseconds delay=std::chrono::milliseconds(1000))
Factory function for fixed delay config.
retry_config create_fibonacci_backoff_config(size_t max_attempts=3, std::chrono::milliseconds initial_delay=std::chrono::milliseconds(1000))
Factory function for Fibonacci backoff config.
retry_config create_exponential_backoff_config(size_t max_attempts=3, std::chrono::milliseconds initial_delay=std::chrono::milliseconds(1000))
Factory function for exponential backoff config.
Result pattern type definitions for monitoring system.
Extended error information with context.
static error_info from_common_error(const common::error_info &common_err)
Create from common_system error_info.
std::chrono::milliseconds initial_delay
std::chrono::milliseconds max_delay
std::function< bool(const error_info &)> should_retry
bool validate() const
Validate configuration.