AMPS C/C++ Client Class Reference
AMPS C/C++ Client Version 5.3.3.0
ReconnectDelayStrategyImpl.hpp
1 //
3 // Copyright (c) 2010-2021 60East Technologies Inc., All Rights Reserved.
4 //
5 // This computer software is owned by 60East Technologies Inc. and is
6 // protected by U.S. copyright laws and other laws and by international
7 // treaties. This computer software is furnished by 60East Technologies
8 // Inc. pursuant to a written license agreement and may be used, copied,
9 // transmitted, and stored only in accordance with the terms of such
10 // license agreement and with the inclusion of the above copyright notice.
11 // This computer software or any other copies thereof may not be provided
12 // or otherwise made available to any other person.
13 //
14 // U.S. Government Restricted Rights. This computer software: (a) was
15 // developed at private expense and is in all respects the proprietary
16 // information of 60East Technologies Inc.; (b) was not developed with
17 // government funds; (c) is a trade secret of 60East Technologies Inc.
18 // for all purposes of the Freedom of Information Act; and (d) is a
19 // commercial item and thus, pursuant to Section 12.212 of the Federal
20 // Acquisition Regulations (FAR) and DFAR Supplement Section 227.7202,
21 // Government's use, duplication or disclosure of the computer software
22 // is subject to the restrictions set forth by 60East Technologies Inc..
23 //
25 
26 #ifndef _AMPS_RECONNECTDELAYSTRATEGYIMPL_HPP_
27 #define _AMPS_RECONNECTDELAYSTRATEGYIMPL_HPP_
28 #include <util.hpp>
29 #include <string>
30 
31 #ifdef _WIN32
32 #include <windows.h>
33 #else
34 #include <sys/time.h>
35 #endif
36 
37 #include <math.h>
38 #include <stdexcept>
39 #include <stdio.h>
40 
41 namespace AMPS
42 {
46  class ReconnectDelayStrategyImpl : public RefBody
47  {
48  public:
49  virtual ~ReconnectDelayStrategyImpl(void) {;}
50 
63  virtual unsigned int getConnectWaitDuration(
64  const std::string& uri_) = 0;
69  virtual void reset(void) = 0;
70  };
71 
78  {
79  public:
111  unsigned int initialDelay_ = 200,
112  unsigned int maximumDelay_ = 20 * 1000,
113  double backoffExponent_ = 2.0,
114  unsigned int maximumRetryTime_= 0,
115  double jitter_ = 1.0)
116  : _initialDelay(initialDelay_),
117  _maximumDelay(maximumDelay_),
118  _backoffExponent(backoffExponent_),
119  _jitter(jitter_),
120  _maximumRetryTime(maximumRetryTime_),
121  _timer(maximumRetryTime_)
122  {
123  if(_jitter > 0.0)
124  {
125  ::srand((unsigned int)amps_now());
126  }
127  }
128 
129  unsigned int getConnectWaitDuration(const std::string& uri_)
130  {
131  _throwIfMaximumExceeded();
132  URIDelayMapIterator currentDelay = _currentDelays.find(uri_);
133  if (currentDelay == _currentDelays.end())
134  {
135  // Is this our first attempt?
136  if (_maximumRetryTime != 0 && _currentDelays.empty())
137  {
138  _timer.start();
139  }
140  // New URI so delay will be zero
141  _currentDelays[uri_] = 0;
142  return 0;
143  }
144  // We've tried this one before, so increase it and return with jitter
145  return _currentDurationAndIncrease(&(currentDelay->second));
146  }
147  void reset(void)
148  {
149  _currentDelays.clear();
150  _timer.reset();
151  }
152 
153  protected:
154 
155  void _throwError(void)
156  {
157  throw ReconnectMaximumExceededException(
158  "The maximum time to attempt "
159  "connection to a server has been exceeded.");
160  }
161 
162  void _throwIfMaximumExceeded(void)
163  {
164  if (_timer.check())
165  {
166  _throwError();
167  }
168  }
169 
170  unsigned int _currentDurationAndIncrease(unsigned int* pCurrentDelay_)
171  {
172  // Calculate the increase to the base delay
173  unsigned long long newDelay = (*pCurrentDelay_ == 0) ?
174  (unsigned long long)_initialDelay :
175  (unsigned long long)(*pCurrentDelay_ * _backoffExponent);
176  if (newDelay > _maximumDelay) newDelay = _maximumDelay;
177  // Save the base delay
178  *pCurrentDelay_ = (unsigned int)newDelay;
179  // Add jitter, if any, for current delay
180  unsigned int delay = (unsigned int)newDelay;
181  unsigned int maxJitter = (unsigned int)(_initialDelay * _jitter);
182  if(_jitter > 0.0)
183  {
184  if (delay > _maximumDelay - maxJitter)
185  delay = (_maximumDelay - maxJitter > _initialDelay) ?
186  _maximumDelay - maxJitter : _initialDelay;
187  delay +=
188  (unsigned int)(_initialDelay * _jitter * (::rand()*1.0/RAND_MAX));
189  if (delay > _maximumDelay) delay = _maximumDelay;
190  }
191  // Avoid delaying past any configured max retry time.
192  if(_maximumRetryTime)
193  {
194  double remaining = 0.0;
195  if (_timer.checkAndGetRemaining(&remaining)) _throwError();
196  unsigned int remainingMillis = (unsigned int)remaining+1U;
197  if (remainingMillis < delay)
198  delay = remainingMillis;
199  }
200  return delay;
201  }
202 
203  unsigned int _initialDelay;
204  unsigned int _maximumDelay;
205  double _backoffExponent;
206  double _jitter;
207  unsigned int _maximumRetryTime;
208  typedef std::map<std::string, unsigned int> URIDelayMap;
209  typedef std::map<std::string, unsigned int>::iterator URIDelayMapIterator;
210  URIDelayMap _currentDelays;
211  Timer _timer;
212  };
213 
221  {
222  public:
233  FixedDelayStrategy(unsigned int duration_ = 200, unsigned maximum_ = 0)
234  : _duration(duration_),
235  _maximum(maximum_),
236  _timer(maximum_)
237  {;}
238 
251  unsigned int getConnectWaitDuration(const std::string& uri_)
252  {
253  double remaining = 0.0;
254  if(_maximum > 0)
255  {
256  // Start the timer
257  if(_triedURIs.empty())
258  {
259  _timer.start();
260  }
261  // or check for max retry time exceeded
262  else if (_timer.checkAndGetRemaining(&remaining))
263  {
264  throw ReconnectMaximumExceededException(
265  "The maximum time to attempt "
266  "connection to a server has been exceeded.");
267  }
268  }
269  // Only wait to reconnect to a repeat server.
270  if (_triedURIs.count(uri_) == 0)
271  {
272  _triedURIs.insert(uri_);
273  return 0;
274  }
275  // Check for max retry time exceeded after delay
276  if (_maximum > 0 && remaining <= _duration)
277  {
278  throw ReconnectMaximumExceededException(
279  "The maximum time to attempt connection to a server "
280  "would be exceeded by another delay.");
281  }
282  // We're trying to reconnect to a previously tried address, delay.
283  return _duration;
284  }
285 
290  void reset(void)
291  {
292  // Forget the last and first so we get one immediate reconnect
293  // attempt if we try this server again.
294  _triedURIs.clear();
295  _timer.reset();
296  }
297 
298  private:
299  unsigned int _duration;
300  unsigned int _maximum;
301  std::set<std::string> _triedURIs;
302  Timer _timer;
303  };
304 }
305 #endif // _AMPS_RECONNECTDELAYSTRATEGYIMPL_HPP_
306 
FixedDelayStrategy(unsigned int duration_=200, unsigned maximum_=0)
Construct a FixedDelayStrategy with a given duration.
Definition: ReconnectDelayStrategyImpl.hpp:233
ExponentialDelayStrategy is an implementation that exponentially "backs off" when reconnecting to the...
Definition: ReconnectDelayStrategyImpl.hpp:77
virtual unsigned int getConnectWaitDuration(const std::string &uri_)=0
Returns the time that the client should delay before connecting to the given server URI...
Base class for ReconnectDelayStrategy implementations.
Definition: ReconnectDelayStrategyImpl.hpp:46
void reset(void)
Reset the state of this reconnect delay.
Definition: ReconnectDelayStrategyImpl.hpp:290
unsigned int getConnectWaitDuration(const std::string &uri_)
Returns the time that the client should delay before connecting to the given server URI...
Definition: ReconnectDelayStrategyImpl.hpp:129
ExponentialDelayStrategy(unsigned int initialDelay_=200, unsigned int maximumDelay_=20 *1000, double backoffExponent_=2.0, unsigned int maximumRetryTime_=0, double jitter_=1.0)
Constructs an exponential delay strategy, the default strategy for HAClient.
Definition: ReconnectDelayStrategyImpl.hpp:110
FixedDelayStrategy is an implementation that delays for a fixed time period, as specified in the cons...
Definition: ReconnectDelayStrategyImpl.hpp:220
unsigned int getConnectWaitDuration(const std::string &uri_)
Returns the time that the client should delay before connecting to the given server URI...
Definition: ReconnectDelayStrategyImpl.hpp:251
virtual void reset(void)=0
Reset the state of this reconnect delay.
void reset(void)
Reset the state of this reconnect delay.
Definition: ReconnectDelayStrategyImpl.hpp:147
Definition: ampsplusplus.hpp:103