Thread System 0.3.1
High-performance C++20 thread pool with work stealing and DAG scheduling
Loading...
Searching...
No Matches
retry_policy.h
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2024, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
12#pragma once
13
14#include <chrono>
15#include <cstddef>
16#include <algorithm>
17#include <cmath>
18#include <functional>
19#include <limits>
20#include <string>
21
22namespace kcenon::thread
23{
28 enum class retry_strategy
29 {
30 none,
31 fixed,
32 linear,
34 };
35
67 {
68 public:
74 , max_attempts_(1)
75 , initial_delay_(std::chrono::milliseconds(0))
76 , multiplier_(1.0)
77 , max_delay_(std::chrono::milliseconds(0))
78 , use_jitter_(false)
80 {
81 }
82
87 [[nodiscard]] static auto no_retry() -> retry_policy
88 {
89 return retry_policy();
90 }
91
101 [[nodiscard]] static auto fixed(
102 std::size_t max_attempts,
103 std::chrono::milliseconds delay) -> retry_policy
104 {
105 retry_policy policy;
107 policy.max_attempts_ = max_attempts;
108 policy.initial_delay_ = delay;
109 policy.multiplier_ = 1.0;
110 policy.max_delay_ = delay;
111 return policy;
112 }
113
124 [[nodiscard]] static auto linear(
125 std::size_t max_attempts,
126 std::chrono::milliseconds initial_delay,
127 std::chrono::milliseconds max_delay = std::chrono::milliseconds::max()) -> retry_policy
128 {
129 retry_policy policy;
131 policy.max_attempts_ = max_attempts;
132 policy.initial_delay_ = initial_delay;
133 policy.multiplier_ = 1.0;
134 policy.max_delay_ = max_delay;
135 return policy;
136 }
137
153 [[nodiscard]] static auto exponential_backoff(
154 std::size_t max_attempts,
155 std::chrono::milliseconds initial_delay = std::chrono::milliseconds(100),
156 double multiplier = 2.0,
157 std::chrono::milliseconds max_delay = std::chrono::milliseconds(30000),
158 bool use_jitter = false) -> retry_policy
159 {
160 retry_policy policy;
162 policy.max_attempts_ = max_attempts;
163 policy.initial_delay_ = initial_delay;
164 policy.multiplier_ = multiplier;
165 policy.max_delay_ = max_delay;
166 policy.use_jitter_ = use_jitter;
167 return policy;
168 }
169
174 [[nodiscard]] auto get_strategy() const -> retry_strategy
175 {
176 return strategy_;
177 }
178
183 [[nodiscard]] auto get_max_attempts() const -> std::size_t
184 {
185 return max_attempts_;
186 }
187
192 [[nodiscard]] auto get_initial_delay() const -> std::chrono::milliseconds
193 {
194 return initial_delay_;
195 }
196
201 [[nodiscard]] auto get_multiplier() const -> double
202 {
203 return multiplier_;
204 }
205
210 [[nodiscard]] auto get_max_delay() const -> std::chrono::milliseconds
211 {
212 return max_delay_;
213 }
214
219 [[nodiscard]] auto uses_jitter() const -> bool
220 {
221 return use_jitter_;
222 }
223
228 [[nodiscard]] auto is_retry_enabled() const -> bool
229 {
231 }
232
237 [[nodiscard]] auto get_current_attempt() const -> std::size_t
238 {
239 return current_attempt_;
240 }
241
246 [[nodiscard]] auto has_attempts_remaining() const -> bool
247 {
248 return current_attempt_ < max_attempts_ - 1;
249 }
250
257 auto record_attempt() -> void
258 {
260 }
261
265 auto reset() -> void
266 {
268 }
269
277 [[nodiscard]] auto get_delay_for_current_attempt() const -> std::chrono::milliseconds
278 {
280 {
281 return std::chrono::milliseconds(0);
282 }
283
284 std::chrono::milliseconds delay;
285
286 switch (strategy_)
287 {
290 break;
291
293 delay = std::chrono::milliseconds(
294 initial_delay_.count() * static_cast<long long>(current_attempt_)
295 );
296 break;
297
299 {
300 double factor = std::pow(multiplier_, static_cast<double>(current_attempt_ - 1));
301 auto calculated = static_cast<long long>(
302 static_cast<double>(initial_delay_.count()) * factor
303 );
304 delay = std::chrono::milliseconds(calculated);
305 }
306 break;
307
308 default:
309 delay = std::chrono::milliseconds(0);
310 break;
311 }
312
313 // Apply max_delay cap
314 if (delay > max_delay_)
315 {
317 }
318
319 return delay;
320 }
321
326 [[nodiscard]] auto to_string() const -> std::string
327 {
328 switch (strategy_)
329 {
331 return "retry_policy(none)";
333 return "retry_policy(fixed, attempts=" + std::to_string(max_attempts_) +
334 ", delay=" + std::to_string(initial_delay_.count()) + "ms)";
336 return "retry_policy(linear, attempts=" + std::to_string(max_attempts_) +
337 ", initial=" + std::to_string(initial_delay_.count()) + "ms)";
339 return "retry_policy(exponential, attempts=" + std::to_string(max_attempts_) +
340 ", initial=" + std::to_string(initial_delay_.count()) +
341 "ms, multiplier=" + std::to_string(multiplier_) + ")";
342 default:
343 return "retry_policy(unknown)";
344 }
345 }
346
347 private:
349 std::size_t max_attempts_;
350 std::chrono::milliseconds initial_delay_;
352 std::chrono::milliseconds max_delay_;
354 std::size_t current_attempt_;
355 };
356
357} // namespace kcenon::thread
Encapsulates retry behavior configuration for jobs.
std::chrono::milliseconds max_delay_
auto reset() -> void
Resets the attempt counter to zero.
auto get_max_delay() const -> std::chrono::milliseconds
Gets the maximum delay cap.
auto record_attempt() -> void
Increments the attempt counter.
static auto linear(std::size_t max_attempts, std::chrono::milliseconds initial_delay, std::chrono::milliseconds max_delay=std::chrono::milliseconds::max()) -> retry_policy
Creates a linear backoff retry policy.
std::chrono::milliseconds initial_delay_
auto has_attempts_remaining() const -> bool
Checks if more retry attempts are available.
static auto fixed(std::size_t max_attempts, std::chrono::milliseconds delay) -> retry_policy
Creates a fixed delay retry policy.
auto get_strategy() const -> retry_strategy
Gets the retry strategy type.
auto get_current_attempt() const -> std::size_t
Gets the current attempt number (0-based).
auto get_delay_for_current_attempt() const -> std::chrono::milliseconds
Calculates the delay for the current retry attempt.
auto uses_jitter() const -> bool
Checks if jitter is enabled.
retry_policy()
Default constructor creates a "no retry" policy.
auto is_retry_enabled() const -> bool
Checks if retry is enabled.
static auto exponential_backoff(std::size_t max_attempts, std::chrono::milliseconds initial_delay=std::chrono::milliseconds(100), double multiplier=2.0, std::chrono::milliseconds max_delay=std::chrono::milliseconds(30000), bool use_jitter=false) -> retry_policy
Creates an exponential backoff retry policy.
static auto no_retry() -> retry_policy
Creates a policy that disables retry.
auto to_string() const -> std::string
Provides a string representation of the policy.
auto get_initial_delay() const -> std::chrono::milliseconds
Gets the initial delay between retries.
auto get_max_attempts() const -> std::size_t
Gets the maximum number of attempts.
auto get_multiplier() const -> double
Gets the multiplier used for exponential backoff.
@ delay
Delay processing (attempt later)
@ none
Below low_watermark, queue is healthy.
Core threading foundation of the thread system library.
Definition thread_impl.h:17
retry_strategy
Defines the strategy for calculating delay between retry attempts.
@ linear
Linearly increasing delay.
@ exponential_backoff
Exponentially increasing delay with optional jitter.
@ fixed
Fixed delay between retries.
STL namespace.