26#include <initializer_list>
32#include "iceberg/iceberg_export.h"
33#include "iceberg/result.h"
46concept ResultType = IsResult<std::remove_cvref_t<T>>::value;
54using RetryTaskResult = std::remove_cvref_t<std::invoke_result_t<F&>>;
61 int32_t num_retries = 4;
63 int32_t min_wait_ms = 100;
65 int32_t max_wait_ms = 60 * 1000;
67 int32_t total_timeout_ms = 30 * 60 * 1000;
69 double scale_factor = 2.0;
89 retry_policy_mode_ = RetryPolicyMode::kOnlyRetryOn;
90 retry_error_kinds_ = std::vector<ErrorKind>(error_kinds);
108 if (retry_policy_mode_ == RetryPolicyMode::kOnlyRetryOn) {
112 retry_policy_mode_ = RetryPolicyMode::kStopRetryOn;
113 retry_error_kinds_ = std::vector<ErrorKind>(error_kinds);
129 template <
typename F>
131 auto Run(F&& task, int32_t* attempt_counter =
nullptr) -> detail::RetryTaskResult<F> {
132 using TaskResult = detail::RetryTaskResult<F>;
134 const auto validation = ValidateConfig();
135 if (!validation.has_value()) {
136 return TaskResult(std::unexpected(validation.error()));
139 const auto deadline = ComputeDeadline();
141 const int32_t max_attempts = config_.num_retries + 1;
145 if (attempt_counter !=
nullptr) {
146 *attempt_counter = attempt;
149 auto result = std::invoke(task);
150 if (result.has_value()) {
154 if (!CanRetry(result.error().kind, attempt, max_attempts, deadline)) {
158 if (!WaitForNextAttempt(attempt, deadline)) {
165 enum class RetryPolicyMode {
174 using Clock = std::chrono::steady_clock;
175 using Duration = std::chrono::milliseconds;
176 using TimePoint = Clock::time_point;
179 Status ValidateConfig()
const;
180 std::optional<TimePoint> ComputeDeadline()
const;
181 bool HasTimedOut(
const std::optional<TimePoint>& deadline)
const;
184 bool ShouldRetry(ErrorKind kind)
const;
185 bool CanRetry(ErrorKind kind, int32_t attempt, int32_t max_attempts,
186 const std::optional<TimePoint>& deadline)
const;
187 std::optional<Duration> RetryDelayWithinBudget(
188 int32_t attempt,
const std::optional<TimePoint>& deadline)
const;
189 bool WaitForNextAttempt(int32_t attempt,
190 const std::optional<TimePoint>& deadline)
const;
192 int32_t CalculateDelay(int32_t attempt)
const;
195 RetryPolicyMode retry_policy_mode_ = RetryPolicyMode::kUnset;
196 std::vector<ErrorKind> retry_error_kinds_;
200ICEBERG_EXPORT
inline RetryRunner MakeCommitRetryRunner(int32_t num_retries,
203 int32_t total_timeout_ms) {
204 return RetryRunner(RetryConfig{.num_retries = num_retries,
205 .min_wait_ms = min_wait_ms,
206 .max_wait_ms = max_wait_ms,
207 .total_timeout_ms = total_timeout_ms})
208 .OnlyRetryOn(ErrorKind::kCommitFailed);
Utility class for running tasks with retry logic.
Definition retry_util.h:76
RetryRunner(RetryConfig config={})
Construct a RetryRunner with the given configuration.
Definition retry_util.h:79
auto Run(F &&task, int32_t *attempt_counter=nullptr) -> detail::RetryTaskResult< F >
Run a task that returns a Result<T>
Definition retry_util.h:131
RetryRunner & StopRetryOn(std::initializer_list< ErrorKind > error_kinds)
Specify error types that should stop retries immediately.
Definition retry_util.h:107
RetryRunner & StopRetryOn(ErrorKind error_kind)
Specify a single error type that should stop retries immediately.
Definition retry_util.h:121
RetryRunner & OnlyRetryOn(std::initializer_list< ErrorKind > error_kinds)
Specify error types that should trigger a retry.
Definition retry_util.h:88
RetryRunner & OnlyRetryOn(ErrorKind error_kind)
Specify a single error type that should trigger a retry.
Definition retry_util.h:98
Definition retry_util.h:46
Definition retry_util.h:49
Configuration for retry behavior.
Definition retry_util.h:59
Definition retry_util.h:40