@@ -179,15 +179,6 @@ std::unique_ptr<SocketFactory> GetSocketFactory(const ClientOptions& opts) {
179179 return std::make_unique<NonSecureSocketFactory>();
180180}
181181
182- std::unique_ptr<EndpointsIteratorBase> GetEndpointsIterator (const ClientOptions& opts) {
183- if (opts.endpoints .empty ())
184- {
185- throw ValidationError (" The list of endpoints is empty" );
186- }
187-
188- return std::make_unique<RoundRobinEndpointsIterator>(opts.endpoints );
189- }
190-
191182} // anonymous namespace
192183
193184class Client ::Impl {
@@ -269,8 +260,6 @@ class Client::Impl {
269260 // / call fuc several times.
270261 void RetryGuard (std::function<void ()> func);
271262
272- void RetryConnectToTheEndpoint (std::function<void ()>& func);
273-
274263private:
275264 enum class State : uint8_t {
276265 Idle = 0 ,
@@ -312,6 +301,8 @@ class Client::Impl {
312301 std::unique_ptr<SocketBase> socket_;
313302 std::unique_ptr<EndpointsIteratorBase> endpoints_iterator;
314303
304+ // current_endpoint_ points to the last successfully connected endpoint, and always
305+ // holds a value. The variable remain wrapped as optional for backwards compatibility.
315306 std::optional<Endpoint> current_endpoint_;
316307
317308 ServerInfo server_info_;
@@ -337,7 +328,8 @@ Client::Impl::Impl(const ClientOptions& opts,
337328 : options_(modifyClientOptions(opts))
338329 , events_(nullptr )
339330 , socket_factory_(std::move(socket_factory))
340- , endpoints_iterator(GetEndpointsIterator(options_))
331+ , endpoints_iterator(std::make_unique<RoundRobinEndpointsIterator>(options_.endpoints))
332+ , current_endpoint_(endpoints_iterator->Next ())
341333{
342334 CreateConnection ();
343335
@@ -614,36 +606,39 @@ void Client::Impl::ResetConnection() {
614606}
615607
616608void Client::Impl::ResetConnectionEndpoint () {
617- current_endpoint_. reset () ;
618- for (size_t i = 0 ; i < options_. endpoints . size (); )
609+ std::optional<Endpoint> last_endpoint = current_endpoint_;
610+ for (size_t i = 1 ; ; ++i )
619611 {
620612 try
621613 {
622- current_endpoint_ = endpoints_iterator->Next ();
623614 ResetConnection ();
624615 return ;
625616 } catch (const std::system_error&) {
626- if (++i == options_.endpoints .size ())
617+ current_endpoint_ = endpoints_iterator->Next ();
618+ if (i >= options_.endpoints .size ())
627619 {
628- current_endpoint_. reset () ;
620+ current_endpoint_ = last_endpoint ;
629621 throw ;
630622 }
623+ } catch (...) {
624+ current_endpoint_ = last_endpoint;
625+ throw ;
631626 }
632627 }
633628}
634629
635630void Client::Impl::CreateConnection () {
636631 // make sure to try to connect to each endpoint at least once even if `options_.send_retries` is 0
637632 const size_t max_attempts = (options_.send_retries ? options_.send_retries : 1 );
638- for (size_t i = 0 ; i < max_attempts; )
633+ for (size_t i = 1 ; ; ++i )
639634 {
640635 try
641636 {
642637 // Try to connect to each endpoint before throwing exception.
643638 ResetConnectionEndpoint ();
644639 return ;
645640 } catch (const std::system_error&) {
646- if (++ i >= max_attempts)
641+ if (i >= max_attempts)
647642 {
648643 throw ;
649644 }
@@ -1227,33 +1222,36 @@ bool Client::Impl::ReceiveHello() {
12271222
12281223void Client::Impl::RetryGuard (std::function<void ()> func) {
12291224
1230- if (current_endpoint_)
1231- {
1232- for (unsigned int i = 0 ; ; ++i) {
1233- try {
1234- func ();
1235- return ;
1236- } catch (const std::system_error&) {
1237- bool ok = true ;
1225+ for (unsigned int i = 1 ; ; ++i) {
1226+ try {
1227+ func ();
1228+ return ;
1229+ } catch (const std::system_error&) {
1230+ // if send_retries == 0 do not try anymore, throw right away
1231+ if (options_.send_retries == 0 ) {
1232+ throw ;
1233+ }
12381234
1239- try {
1240- socket_factory_->sleepFor (options_.retry_timeout );
1241- ResetConnection ();
1242- } catch (...) {
1243- ok = false ;
1244- }
1235+ // If `send_retries` attempts failed, try other endpoints
1236+ if (i >= options_.send_retries ) {
1237+ break ;
1238+ }
12451239
1246- if (!ok && i == options_.send_retries ) {
1247- break ;
1248- }
1240+ // otherwise sleep and try again
1241+ try {
1242+ socket_factory_->sleepFor (options_.retry_timeout );
1243+ ResetConnection ();
1244+ } catch (const std::system_error&) {
12491245 }
1246+
12501247 }
12511248 }
1249+
12521250 // Connections with current_endpoint_ are broken.
1253- // Trying to establish with the another one from the list.
1251+ // Trying to establish with another one from the list.
12541252 size_t connection_attempts_count = options_.endpoints .size () * options_.send_retries ;
1255-
1256- for (size_t i = 0 ; i < connection_attempts_count; )
1253+ std::optional<Endpoint> last_endpoint = current_endpoint_;
1254+ for (size_t i = 1 ; ; ++i )
12571255 {
12581256 try
12591257 {
@@ -1263,11 +1261,14 @@ void Client::Impl::RetryGuard(std::function<void()> func) {
12631261 func ();
12641262 return ;
12651263 } catch (const std::system_error&) {
1266- if (++i = = connection_attempts_count)
1264+ if (i > = connection_attempts_count)
12671265 {
1268- current_endpoint_. reset () ;
1266+ current_endpoint_ = last_endpoint ;
12691267 throw ;
12701268 }
1269+ } catch (...) {
1270+ current_endpoint_ = last_endpoint;
1271+ throw ;
12711272 }
12721273 }
12731274}
0 commit comments