AMPS C/C++ Client Class Reference
AMPS C/C++ Client Version 5.3.3.4
ReconnectDelayStrategyImpl.hpp
1 //
3 // Copyright (c) 2010-2023 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)
177  {
178  newDelay = _maximumDelay;
179  }
180  // Save the base delay
181  *pCurrentDelay_ = (unsigned int)newDelay;
182  // Add jitter, if any, for current delay
183  unsigned int delay = (unsigned int)newDelay;
184  unsigned int maxJitter = (unsigned int)(_initialDelay * _jitter);
185  if (_jitter > 0.0)
186  {
187  if (delay > _maximumDelay - maxJitter)
188  delay = (_maximumDelay - maxJitter > _initialDelay) ?
189  _maximumDelay - maxJitter : _initialDelay;
190  delay +=
191  (unsigned int)(_initialDelay * _jitter * (::rand() * 1.0 / RAND_MAX));
192  if (delay > _maximumDelay)
193  {
194  delay = _maximumDelay;
195  }
196  }
197  // Avoid delaying past any configured max retry time.
198  if (_maximumRetryTime)
199  {
200  double remaining = 0.0;
201  if (_timer.checkAndGetRemaining(&remaining))
202  {
203  _throwError();
204  }
205  unsigned int remainingMillis = (unsigned int)remaining + 1U;
206  if (remainingMillis < delay)
207  {
208  delay = remainingMillis;
209  }
210  }
211  return delay;
212  }
213 
214  unsigned int _initialDelay;
215  unsigned int _maximumDelay;
216  double _backoffExponent;
217  double _jitter;
218  unsigned int _maximumRetryTime;
219  typedef std::map<std::string, unsigned int> URIDelayMap;
220  typedef std::map<std::string, unsigned int>::iterator URIDelayMapIterator;
221  URIDelayMap _currentDelays;
222  Timer _timer;
223  };
224 
232  {
233  public:
244  FixedDelayStrategy(unsigned int duration_ = 200, unsigned maximum_ = 0)
245  : _duration(duration_),
246  _maximum(maximum_),
247  _timer(maximum_)
248  {;}
249 
262  unsigned int getConnectWaitDuration(const std::string& uri_)
263  {
264  double remaining = 0.0;
265  if (_maximum > 0)
266  {
267  // Start the timer
268  if (_triedURIs.empty())
269  {
270  _timer.start();
271  }
272  // or check for max retry time exceeded
273  else if (_timer.checkAndGetRemaining(&remaining))
274  {
275  throw ReconnectMaximumExceededException(
276  "The maximum time to attempt "
277  "connection to a server has been exceeded.");
278  }
279  }
280  // Only wait to reconnect to a repeat server.
281  if (_triedURIs.count(uri_) == 0)
282  {
283  _triedURIs.insert(uri_);
284  return 0;
285  }
286  // Check for max retry time exceeded after delay
287  if (_maximum > 0 && remaining <= _duration)
288  {
289  throw ReconnectMaximumExceededException(
290  "The maximum time to attempt connection to a server "
291  "would be exceeded by another delay.");
292  }
293  // We're trying to reconnect to a previously tried address, delay.
294  return _duration;
295  }
296 
301  void reset(void)
302  {
303  // Forget the last and first so we get one immediate reconnect
304  // attempt if we try this server again.
305  _triedURIs.clear();
306  _timer.reset();
307  }
308 
309  private:
310  unsigned int _duration;
311  unsigned int _maximum;
312  std::set<std::string> _triedURIs;
313  Timer _timer;
314  };
315 }
316 #endif // _AMPS_RECONNECTDELAYSTRATEGYIMPL_HPP_
317 
FixedDelayStrategy(unsigned int duration_=200, unsigned maximum_=0)
Construct a FixedDelayStrategy with a given duration.
Definition: ReconnectDelayStrategyImpl.hpp:244
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:301
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:231
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:262
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