AWS SDK for C++

AWS SDK for C++ Version 1.11.785

Loading...
Searching...
No Matches
Waiter.h
1
6#pragma once
7
8#include <aws/core/utils/logging/LogMacros.h>
9#include <aws/crt/Variant.h>
10
11#include <algorithm>
12#include <functional>
13#include <aws/core/utils/memory/AWSMemory.h>
14#include <utility>
15#include <thread>
16#include <type_traits>
17
18namespace Aws {
19namespace Utils {
20
23
24using ExpectedValue = Crt::Variant<int, bool, Aws::String>;
26
27template <typename OutcomeT>
29
30template <typename OutcomeT>
31struct Acceptor {
33 explicit Acceptor(WaiterState s) : state(s) {}
34 virtual ~Acceptor() = default;
35 virtual bool Matches(const OutcomeT& outcome) const = 0;
36};
37
38template <typename OutcomeT>
39struct StatusAcceptor : Acceptor<OutcomeT> {
41 StatusAcceptor(WaiterState s, int status) : Acceptor<OutcomeT>(s), expectedStatus(status) {}
42 bool Matches(const OutcomeT& outcome) const override {
43 return GetStatusCode(outcome) == expectedStatus;
44 }
45
46 private:
47 template<typename T>
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;
52 };
53 template<typename T>
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;
58 };
59 template<typename T>
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());
63 }
64 template<typename T>
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());
68 }
69 static int GetStatusCode(const OutcomeT& outcome) {
70 return outcome.IsSuccess()
71 ? GetStatusCodeFromResult(outcome.GetResult())
72 : GetStatusCodeFromError(outcome.GetError());
73 }
74};
75
76template <typename OutcomeT>
77struct ErrorAcceptor : Acceptor<OutcomeT> {
79 ErrorAcceptor(WaiterState s, ExpectedValue e) : Acceptor<OutcomeT>(s), expected(std::move(e)) {}
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>();
83 }
84 if (!outcome.IsSuccess()) {
85 return outcome.GetError().GetExceptionName() == this->expected.template get<Aws::String>();
86 }
87 return false;
88 }
89};
90
91template <typename OutcomeT>
92using PathMatcherFn = std::function<bool(const OutcomeT&, const ExpectedValue&)>;
93
94template <typename OutcomeT>
95struct PathAcceptor : Acceptor<OutcomeT> {
99 : Acceptor<OutcomeT>(s), expected(std::move(e)), pathMatcher(std::move(pm)) {}
100 bool Matches(const OutcomeT& outcome) const override {
101 return pathMatcher ? pathMatcher(outcome, expected) : false;
102 }
103};
104
105
106template <typename RequestT, typename OutcomeT>
107class Waiter {
108 public:
110
111 Waiter(int delay, int maxAttempts, Aws::Vector<AcceptorPtr> acceptors, std::function<OutcomeT(const RequestT&)> op,
112 const Aws::String& waiterName = "Waiter")
113 : m_delay(delay),
114 m_maxAttempts(maxAttempts),
115 m_acceptors(std::move(acceptors)),
116 m_operation(std::move(op)),
117 m_name(waiterName) {}
118
119 WaiterOutcome<OutcomeT> Wait(const RequestT& request) {
120 request.AddUserAgentFeature(Aws::Client::UserAgentFeature::WAITER);
121 for (int attempt = 0; attempt < m_maxAttempts; ++attempt) {
122 auto outcome = m_operation(request);
123
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) {
129 return WaiterOutcome<OutcomeT>(outcome);
132 "Waiter matched a failure acceptor", false /*retryable*/));
134 break; // continue polling
135 }
136 } else if (!outcome.IsSuccess()) {
137 // No acceptor matched and an error was encountered: transition to failure
139 "No acceptor matched and an error was encountered", false /*retryable*/));
140 }
141
142 if (attempt < m_maxAttempts - 1) {
143 std::this_thread::sleep_for(std::chrono::seconds(m_delay));
144 }
145 }
146 AWS_LOG_TRACE(m_name.c_str(), "Waiter hit max attempts");
147 return WaiterOutcome<OutcomeT>(WaiterError(WaiterErrors::MAX_ATTEMPTS, "", "Max attempts for operation reached", false /*retryable*/));
148 }
149
150private:
151 int m_delay;
152 int m_maxAttempts;
153 Aws::Vector<AcceptorPtr> m_acceptors;
154 std::function<OutcomeT(const RequestT&)> m_operation;
155 Aws::String m_name;
156
157};
158} // namespace Utils
159} // namespace Aws
WaiterOutcome< OutcomeT > Wait(const RequestT &request)
Definition Waiter.h:119
Aws::UniquePtr< Acceptor< OutcomeT > > AcceptorPtr
Definition Waiter.h:109
Waiter(int delay, int maxAttempts, Aws::Vector< AcceptorPtr > acceptors, std::function< OutcomeT(const RequestT &)> op, const Aws::String &waiterName="Waiter")
Definition Waiter.h:111
std::function< bool(const OutcomeT &, const ExpectedValue &)> PathMatcherFn
Definition Waiter.h:92
Crt::Variant< int, bool, Aws::String > ExpectedValue
Definition Waiter.h:24
Aws::Client::AWSError< WaiterErrors > WaiterError
Definition Waiter.h:25
std::basic_string< char, std::char_traits< char >, Aws::Allocator< char > > String
Definition AWSString.h:97
std::vector< T, Aws::Allocator< T > > Vector
Definition AWSVector.h:17
std::unique_ptr< T, D > UniquePtr
Definition AWSMemory.h:255
WaiterState state
Definition Waiter.h:32
virtual bool Matches(const OutcomeT &outcome) const =0
virtual ~Acceptor()=default
Acceptor(WaiterState s)
Definition Waiter.h:33
ExpectedValue expected
Definition Waiter.h:78
ErrorAcceptor(WaiterState s, ExpectedValue e)
Definition Waiter.h:79
bool Matches(const OutcomeT &outcome) const override
Definition Waiter.h:80
PathAcceptor(WaiterState s, ExpectedValue e, PathMatcherFn< OutcomeT > pm)
Definition Waiter.h:98
PathMatcherFn< OutcomeT > pathMatcher
Definition Waiter.h:97
bool Matches(const OutcomeT &outcome) const override
Definition Waiter.h:100
ExpectedValue expected
Definition Waiter.h:96
bool Matches(const OutcomeT &outcome) const override
Definition Waiter.h:42
StatusAcceptor(WaiterState s, int status)
Definition Waiter.h:41