Skip to content

Commit

Permalink
docs(spanner): document RetryPolicy interface (#12037)
Browse files Browse the repository at this point in the history
  • Loading branch information
coryan committed Jul 6, 2023
1 parent 1833dce commit 4550d52
Showing 1 changed file with 264 additions and 27 deletions.
291 changes: 264 additions & 27 deletions google/cloud/spanner/retry_policy.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,33 +59,270 @@ GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
namespace spanner {
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN

/// The base class for retry policies.
using RetryPolicy = ::google::cloud::internal::TraitBasedRetryPolicy<
spanner_internal::SafeGrpcRetry>;

/// A retry policy that limits based on time.
using LimitedTimeRetryPolicy =
::google::cloud::internal::LimitedTimeRetryPolicy<
spanner_internal::SafeGrpcRetry>;

/// A retry policy that limits the number of times a request can fail.
using LimitedErrorCountRetryPolicy =
google::cloud::internal::LimitedErrorCountRetryPolicy<
spanner_internal::SafeGrpcRetry>;

/// The base class for transaction rerun policies.
using TransactionRerunPolicy = ::google::cloud::internal::TraitBasedRetryPolicy<
spanner_internal::SafeTransactionRerun>;

/// A transaction rerun policy that limits the duration of the rerun loop.
using LimitedTimeTransactionRerunPolicy =
google::cloud::internal::LimitedTimeRetryPolicy<
spanner_internal::SafeTransactionRerun>;

/// A transaction rerun policy that limits the number of failures.
using LimitedErrorCountTransactionRerunPolicy =
google::cloud::internal::LimitedErrorCountRetryPolicy<
spanner_internal::SafeTransactionRerun>;
/// The base class for the Spanner library retry policies.
class RetryPolicy : public google::cloud::RetryPolicy {
public:
/// Creates a new instance of the policy, reset to the initial state.
virtual std::unique_ptr<RetryPolicy> clone() const = 0;
};

/**
* A retry policy for the Spanner library based on counting errors.
*
* This policy stops retrying if:
* - An RPC returns a non-transient error.
* - More than a prescribed number of transient failures is detected.
*
* In this class the following status codes are treated as transient errors:
* - [`kUnavailable`](@ref google::cloud::StatusCode)
* - [`kResourceExhausted`](@ref google::cloud::StatusCode)
* - [`kInternal`](@ref google::cloud::StatusCode) if the error message
* indicates a connection reset.
*/
class LimitedErrorCountRetryPolicy : public RetryPolicy {
public:
/**
* Create an instance that tolerates up to @p maximum_failures transient
* errors.
*
* @note Disable the retry loop by providing an instance of this policy with
* @p maximum_failures == 0.
*/
explicit LimitedErrorCountRetryPolicy(int maximum_failures)
: impl_(maximum_failures) {}

LimitedErrorCountRetryPolicy(LimitedErrorCountRetryPolicy&& rhs) noexcept
: LimitedErrorCountRetryPolicy(rhs.maximum_failures()) {}
LimitedErrorCountRetryPolicy(LimitedErrorCountRetryPolicy const& rhs) noexcept
: LimitedErrorCountRetryPolicy(rhs.maximum_failures()) {}

int maximum_failures() const { return impl_.maximum_failures(); }

bool OnFailure(Status const& s) override { return impl_.OnFailure(s); }
bool IsExhausted() const override { return impl_.IsExhausted(); }
bool IsPermanentFailure(Status const& s) const override {
return impl_.IsPermanentFailure(s);
}
std::unique_ptr<RetryPolicy> clone() const override {
return std::make_unique<LimitedErrorCountRetryPolicy>(
impl_.maximum_failures());
}

// This is provided only for backwards compatibility.
using BaseType = RetryPolicy;

private:
google::cloud::internal::LimitedErrorCountRetryPolicy<
spanner_internal::SafeGrpcRetry>
impl_;
};

/**
* A retry policy for the Spanner library based on elapsed time.
*
* This policy stops retrying if:
* - An RPC returns a non-transient error.
* - The elapsed time in the retry loop exceeds a prescribed duration.
*
* The following status codes are treated as transient errors:
* - [`kUnavailable`](@ref google::cloud::StatusCode)
* - [`kResourceExhausted`](@ref google::cloud::StatusCode)
* - [`kInternal`](@ref google::cloud::StatusCode) if the error message
* indicates a connection reset.
*/
class LimitedTimeRetryPolicy : public RetryPolicy {
public:
/**
* Constructor given a `std::chrono::duration<>` object.
*
* @tparam DurationRep a placeholder to match the `Rep` tparam for
* @p maximum_duration's type. The semantics of this template parameter
* are documented in `std::chrono::duration<>`. In brief, the underlying
* arithmetic type used to store the number of ticks. For our purposes it
* is simply a formal parameter.
* @tparam DurationPeriod a placeholder to match the `Period` tparam for
* @p maximum_duration's type. The semantics of this template parameter
* are documented in `std::chrono::duration<>`. In brief, the length of
* the tick in seconds, expressed as a `std::ratio<>`. For our purposes it
* is simply a formal parameter.
* @param maximum_duration the maximum time allowed before the policy expires,
* while the application can express this time in any units they desire,
* the class truncates to milliseconds.
*
* @see https://en.cppreference.com/w/cpp/chrono/duration for more details
* about `std::chrono::duration`.
*/
template <typename DurationRep, typename DurationPeriod>
explicit LimitedTimeRetryPolicy(
std::chrono::duration<DurationRep, DurationPeriod> maximum_duration)
: impl_(maximum_duration) {}

LimitedTimeRetryPolicy(LimitedTimeRetryPolicy&& rhs) noexcept
: LimitedTimeRetryPolicy(rhs.maximum_duration()) {}
LimitedTimeRetryPolicy(LimitedTimeRetryPolicy const& rhs) noexcept
: LimitedTimeRetryPolicy(rhs.maximum_duration()) {}

std::chrono::milliseconds maximum_duration() const {
return impl_.maximum_duration();
}

std::unique_ptr<RetryPolicy> clone() const override {
return std::make_unique<LimitedTimeRetryPolicy>(impl_.maximum_duration());
}
bool OnFailure(Status const& s) override { return impl_.OnFailure(s); }
bool IsExhausted() const override { return impl_.IsExhausted(); }
bool IsPermanentFailure(Status const& s) const override {
return impl_.IsPermanentFailure(s);
}

// This is provided only for backwards compatibility.
using BaseType = RetryPolicy;

private:
google::cloud::internal::LimitedTimeRetryPolicy<
spanner_internal::SafeGrpcRetry>
impl_;
};

/**
* The base class for the Spanner library transaction rerun policies.
*
* The [`Client::Commit()`] functions (there are several overloads) consume a
* callable to create mutations or a list of mutations. `Commit()` creates a
* transaction and applies the mutations. If the transaction fails, an instance
* of this class is used to control whether the transaction will be attempted
* again.
*
* [`Client::Commit()`]: @ref google::cloud::spanner::Client::Commit()
*/
class TransactionRerunPolicy : public google::cloud::RetryPolicy {
public:
/// Creates a new instance of the policy, reset to the initial state.
virtual std::unique_ptr<TransactionRerunPolicy> clone() const = 0;
};

/**
* A transaction rerun policy based on counting errors.
*
* This policy stops running if:
* - An RPC returns a non-transient error.
* - More than a prescribed number of transient failures is detected.
*
* The following status codes are treated as transient errors:
* - [`kAborted`](@ref google::cloud::StatusCode)
* - [`kNotFound`](@ref google::cloud::StatusCode) when the error message
* indicates the missing (or expired) resource is the spanner session
* associated with the transaction.
*/
class LimitedErrorCountTransactionRerunPolicy : public TransactionRerunPolicy {
public:
/**
* Create an instance that tolerates up to @p maximum_failures transient
* errors.
*
* @note Disable the retry loop by providing an instance of this policy with
* @p maximum_failures == 0.
*/
explicit LimitedErrorCountTransactionRerunPolicy(int maximum_failures)
: impl_(maximum_failures) {}

LimitedErrorCountTransactionRerunPolicy(
LimitedErrorCountTransactionRerunPolicy&& rhs) noexcept
: LimitedErrorCountTransactionRerunPolicy(rhs.maximum_failures()) {}
LimitedErrorCountTransactionRerunPolicy(
LimitedErrorCountTransactionRerunPolicy const& rhs) noexcept
: LimitedErrorCountTransactionRerunPolicy(rhs.maximum_failures()) {}

int maximum_failures() const { return impl_.maximum_failures(); }

bool OnFailure(Status const& s) override { return impl_.OnFailure(s); }
bool IsExhausted() const override { return impl_.IsExhausted(); }
bool IsPermanentFailure(Status const& s) const override {
return impl_.IsPermanentFailure(s);
}
std::unique_ptr<TransactionRerunPolicy> clone() const override {
return std::make_unique<LimitedErrorCountTransactionRerunPolicy>(
impl_.maximum_failures());
}

// This is provided only for backwards compatibility.
using BaseType = TransactionRerunPolicy;

private:
google::cloud::internal::LimitedErrorCountRetryPolicy<
spanner_internal::SafeTransactionRerun>
impl_;
};

/**
* A transaction rerun policy based on elapsed time.
*
* This policy stops retrying if:
* - An RPC returns a non-transient error.
* - The elapsed time in the retry loop exceeds a prescribed duration.
*
* The following status codes are treated as transient errors:
* - [`kAborted`](@ref google::cloud::StatusCode)
* - [`kNotFound`](@ref google::cloud::StatusCode) when the error message
* indicates the missing (or expired) resource is the spanner session
* associated with the transaction.
*/
class LimitedTimeTransactionRerunPolicy : public TransactionRerunPolicy {
public:
/**
* Constructor given a `std::chrono::duration<>` object.
*
* @tparam DurationRep a placeholder to match the `Rep` tparam for
* @p maximum_duration's type. The semantics of this template parameter
* are documented in `std::chrono::duration<>`. In brief, the underlying
* arithmetic type used to store the number of ticks. For our purposes it
* is simply a formal parameter.
* @tparam DurationPeriod a placeholder to match the `Period` tparam for
* @p maximum_duration's type. The semantics of this template parameter
* are documented in `std::chrono::duration<>`. In brief, the length of
* the tick in seconds, expressed as a `std::ratio<>`. For our purposes it
* is simply a formal parameter.
* @param maximum_duration the maximum time allowed before the policy expires,
* while the application can express this time in any units they desire,
* the class truncates to milliseconds.
*
* @see https://en.cppreference.com/w/cpp/chrono/duration for more details
* about `std::chrono::duration`.
*/
template <typename DurationRep, typename DurationPeriod>
explicit LimitedTimeTransactionRerunPolicy(
std::chrono::duration<DurationRep, DurationPeriod> maximum_duration)
: impl_(maximum_duration) {}

LimitedTimeTransactionRerunPolicy(
LimitedTimeTransactionRerunPolicy&& rhs) noexcept
: LimitedTimeTransactionRerunPolicy(rhs.maximum_duration()) {}
LimitedTimeTransactionRerunPolicy(
LimitedTimeTransactionRerunPolicy const& rhs) noexcept
: LimitedTimeTransactionRerunPolicy(rhs.maximum_duration()) {}

std::chrono::milliseconds maximum_duration() const {
return impl_.maximum_duration();
}

bool OnFailure(Status const& s) override { return impl_.OnFailure(s); }
bool IsExhausted() const override { return impl_.IsExhausted(); }
bool IsPermanentFailure(Status const& s) const override {
return impl_.IsPermanentFailure(s);
}
std::unique_ptr<TransactionRerunPolicy> clone() const override {
return std::make_unique<LimitedTimeTransactionRerunPolicy>(
impl_.maximum_duration());
}

// This is provided only for backwards compatibility.
using BaseType = RetryPolicy;

private:
google::cloud::internal::LimitedTimeRetryPolicy<
spanner_internal::SafeTransactionRerun>
impl_;
};

GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
} // namespace spanner
Expand Down

0 comments on commit 4550d52

Please sign in to comment.