8#include <aws/core/utils/logging/LogMacros.h>
9#include <aws/crt/Variant.h>
13#include <aws/core/utils/memory/AWSMemory.h>
27template <
typename OutcomeT>
30template <
typename OutcomeT>
35 virtual bool Matches(
const OutcomeT& outcome)
const = 0;
38template <
typename OutcomeT>
42 bool Matches(
const OutcomeT& outcome)
const override {
48 struct HasGetHttpResponseCode {
49 template<
typename U>
static auto test(
int) ->
decltype(std::declval<U>().GetHttpResponseCode(), std::true_type());
50 template<
typename>
static std::false_type test(...);
51 static constexpr bool value =
decltype(test<T>(0))::value;
54 struct HasGetResponseCode {
55 template<
typename U>
static auto test(
int) ->
decltype(std::declval<U>().GetResponseCode(), std::true_type());
56 template<
typename>
static std::false_type test(...);
57 static constexpr bool value =
decltype(test<T>(0))::value;
60 static int GetStatusCodeFromResult(
const T& result) {
61 static_assert(HasGetHttpResponseCode<T>::value,
"Result type must have GetHttpResponseCode() method");
62 return static_cast<int>(result.GetHttpResponseCode());
65 static int GetStatusCodeFromError(
const T& error) {
66 static_assert(HasGetResponseCode<T>::value,
"Error type must have GetResponseCode() method");
67 return static_cast<int>(error.GetResponseCode());
69 static int GetStatusCode(
const OutcomeT& outcome) {
70 return outcome.IsSuccess()
71 ? GetStatusCodeFromResult(outcome.GetResult())
72 : GetStatusCodeFromError(outcome.GetError());
76template <
typename OutcomeT>
80 bool Matches(
const OutcomeT& outcome)
const override {
81 if (this->expected.template holds_alternative<bool>()) {
82 return outcome.IsSuccess() != this->expected.template get<bool>();
84 if (!outcome.IsSuccess()) {
85 return outcome.GetError().GetExceptionName() == this->expected.template get<Aws::String>();
91template <
typename OutcomeT>
94template <
typename OutcomeT>
100 bool Matches(
const OutcomeT& outcome)
const override {
106template <
typename RequestT,
typename OutcomeT>
114 m_maxAttempts(maxAttempts),
115 m_acceptors(std::move(acceptors)),
116 m_operation(std::move(op)),
117 m_name(waiterName) {}
121 for (
int attempt = 0; attempt < m_maxAttempts; ++attempt) {
122 auto outcome = m_operation(request);
124 auto matched = std::find_if(m_acceptors.begin(), m_acceptors.end(),
125 [&outcome](
const AcceptorPtr& acceptor) ->
bool { return acceptor->Matches(outcome); });
126 if (matched != m_acceptors.end()) {
127 switch (matched->get()->state) {
132 "Waiter matched a failure acceptor",
false ));
136 }
else if (!outcome.IsSuccess()) {
139 "No acceptor matched and an error was encountered",
false ));
142 if (attempt < m_maxAttempts - 1) {
143 std::this_thread::sleep_for(std::chrono::seconds(m_delay));
146 AWS_LOG_TRACE(m_name.c_str(),
"Waiter hit max attempts");
154 std::function<OutcomeT(
const RequestT&)> m_operation;
WaiterOutcome< OutcomeT > Wait(const RequestT &request)
Aws::UniquePtr< Acceptor< OutcomeT > > AcceptorPtr
Waiter(int delay, int maxAttempts, Aws::Vector< AcceptorPtr > acceptors, std::function< OutcomeT(const RequestT &)> op, const Aws::String &waiterName="Waiter")
std::function< bool(const OutcomeT &, const ExpectedValue &)> PathMatcherFn
Crt::Variant< int, bool, Aws::String > ExpectedValue
Aws::Client::AWSError< WaiterErrors > WaiterError
std::basic_string< char, std::char_traits< char >, Aws::Allocator< char > > String
std::vector< T, Aws::Allocator< T > > Vector
std::unique_ptr< T, D > UniquePtr
virtual bool Matches(const OutcomeT &outcome) const =0
virtual ~Acceptor()=default
ErrorAcceptor(WaiterState s, ExpectedValue e)
bool Matches(const OutcomeT &outcome) const override
PathAcceptor(WaiterState s, ExpectedValue e, PathMatcherFn< OutcomeT > pm)
PathMatcherFn< OutcomeT > pathMatcher
bool Matches(const OutcomeT &outcome) const override
bool Matches(const OutcomeT &outcome) const override
StatusAcceptor(WaiterState s, int status)