29#include "iceberg/iceberg_export.h"
30#include "iceberg/result.h"
31#include "iceberg/util/macros.h"
45 int32_t num_retries = 4;
47 int32_t min_wait_ms = 100;
49 int32_t max_wait_ms = 60 * 1000;
51 int32_t total_timeout_ms = 30 * 60 * 1000;
53 double scale_factor = 2.0;
62 using Clock = std::chrono::steady_clock;
63 using Duration = std::chrono::milliseconds;
64 using TimePoint = Clock::time_point;
67 Status ValidateConfig()
const;
68 std::optional<TimePoint> ComputeDeadline()
const;
69 bool HasTimedOut(
const std::optional<TimePoint>& deadline)
const;
70 std::optional<Duration> RetryDelayWithinBudget(
71 int32_t attempt,
const std::optional<TimePoint>& deadline)
const;
72 bool WaitForNextAttempt(int32_t attempt,
73 const std::optional<TimePoint>& deadline)
const;
75 int32_t CalculateDelay(int32_t attempt)
const;
84enum class RetryPolicyMode {
90template <RetryPolicyMode Mode, ErrorKind... Kinds>
92 static_assert(Mode != RetryPolicyMode::kNoRetry ||
sizeof...(Kinds) == 0,
93 "NoRetry must not include error kinds");
94 static_assert(Mode == RetryPolicyMode::kNoRetry ||
sizeof...(Kinds) > 0,
95 "RetryPolicy must include at least one error kind");
97 static constexpr RetryPolicyMode kMode = Mode;
98 static constexpr bool kEnabled = Mode != RetryPolicyMode::kNoRetry;
100 static constexpr bool ShouldRetry(ErrorKind kind) {
101 if constexpr (Mode == RetryPolicyMode::kNoRetry) {
103 }
else if constexpr (Mode == RetryPolicyMode::kOnlyRetryOn) {
104 return ((kind == Kinds) || ...);
106 return !((kind == Kinds) || ...);
111using NoRetry = RetryPolicy<RetryPolicyMode::kNoRetry>;
113template <ErrorKind... Kinds>
114using OnlyRetryOn =
RetryPolicy<RetryPolicyMode::kOnlyRetryOn, Kinds...>;
116template <ErrorKind... Kinds>
117using StopRetryOn =
RetryPolicy<RetryPolicyMode::kStopRetryOn, Kinds...>;
120inline constexpr bool kIsRetryPolicy =
false;
122template <RetryPolicyMode Mode, ErrorKind... Kinds>
123inline constexpr bool kIsRetryPolicy<
RetryPolicy<Mode, Kinds...>> =
true;
126concept Policy = kIsRetryPolicy<std::remove_cvref_t<T>>;
134template <retry::Policy RetryPolicy>
139 : detail::RetryRunnerBase(
std::move(config)) {}
146 template <detail::RetryTask F>
147 auto Run(F&& task, int32_t* attempt_counter =
nullptr)
148 -> std::remove_cvref_t<std::invoke_result_t<F&>> {
149 ICEBERG_RETURN_UNEXPECTED(ValidatePolicyConfig());
151 const auto deadline = this->ComputeDeadline();
153 const int32_t max_attempts = this->config_.num_retries + 1;
157 if (attempt_counter !=
nullptr) {
158 *attempt_counter = attempt;
161 auto result = std::invoke(task);
162 if (result.has_value()) {
166 if (!CanRetry(result.error().kind, attempt, max_attempts, deadline)) {
170 if (!this->WaitForNextAttempt(attempt, deadline)) {
177 using TimePoint = detail::RetryRunnerBase::TimePoint;
179 Status ValidatePolicyConfig()
const {
181 if (!validation.has_value()) {
184 if (this->config_.num_retries > 0 && !RetryPolicy::kEnabled) {
185 return InvalidArgument(
"Retry policy must be enabled when num_retries > 0");
190 bool CanRetry(ErrorKind kind, int32_t attempt, int32_t max_attempts,
191 const std::optional<TimePoint>& deadline)
const {
192 return attempt < max_attempts && !this->HasTimedOut(deadline) &&
193 RetryPolicy::ShouldRetry(kind);
198ICEBERG_EXPORT
inline auto MakeCommitRetryRunner(int32_t num_retries, int32_t min_wait_ms,
200 int32_t total_timeout_ms) {
201 return RetryRunner<retry::OnlyRetryOn<ErrorKind::kCommitFailed,
202 ErrorKind::kRetryableValidationFailed>>(
203 RetryConfig{.num_retries = num_retries,
204 .min_wait_ms = min_wait_ms,
205 .max_wait_ms = max_wait_ms,
206 .total_timeout_ms = total_timeout_ms});
Utility class for running tasks with retry logic.
Definition retry_util.h:135
auto Run(F &&task, int32_t *attempt_counter=nullptr) -> std::remove_cvref_t< std::invoke_result_t< F & > >
Run a task that returns a Result<T>
Definition retry_util.h:147
RetryRunner(RetryConfig config={})
Construct a RetryRunner with the given configuration.
Definition retry_util.h:138
Definition retry_util.h:58
Status ValidateConfig() const
Validate retry counts and timing bounds.
Definition retry_util.cc:83
Definition retry_util.h:38
Definition retry_util.h:126
Configuration for retry behavior.
Definition retry_util.h:43
Definition retry_util.h:91