AMPS C/C++ Client Class Reference AMPS C/C++ Client Version 5.3.5.1

ReconnectDelayStrategyImpl.hpp
1 //
3 // Copyright (c) 2010-2025 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 <amps/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
77 class ExponentialDelayStrategy : public ReconnectDelayStrategyImpl
78 {
79 public:
110 ExponentialDelayStrategy(
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
231 class FixedDelayStrategy : public ReconnectDelayStrategyImpl
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
AMPS::ExponentialDelayStrategy
ExponentialDelayStrategy is an implementation that exponentially "backs off" when reconnecting to the...
Definition: ReconnectDelayStrategyImpl.hpp:78
AMPS::ExponentialDelayStrategy::reset
void reset(void)
Reset the state of this reconnect delay.
Definition: ReconnectDelayStrategyImpl.hpp:147
AMPS::ExponentialDelayStrategy::ExponentialDelayStrategy
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
AMPS::ExponentialDelayStrategy::getConnectWaitDuration
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
AMPS::FixedDelayStrategy
FixedDelayStrategy is an implementation that delays for a fixed time period, as specified in the cons...
Definition: ReconnectDelayStrategyImpl.hpp:232
AMPS::FixedDelayStrategy::getConnectWaitDuration
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
AMPS::FixedDelayStrategy::reset
void reset(void)
Reset the state of this reconnect delay.
Definition: ReconnectDelayStrategyImpl.hpp:301
AMPS::FixedDelayStrategy::FixedDelayStrategy
FixedDelayStrategy(unsigned int duration_=200, unsigned maximum_=0)
Construct a FixedDelayStrategy with a given duration.
Definition: ReconnectDelayStrategyImpl.hpp:244
AMPS::ReconnectDelayStrategyImpl
Base class for ReconnectDelayStrategy implementations.
Definition: ReconnectDelayStrategyImpl.hpp:47
AMPS::ReconnectDelayStrategyImpl::reset
virtual void reset(void)=0
Reset the state of this reconnect delay.
AMPS::ReconnectDelayStrategyImpl::getConnectWaitDuration
virtual unsigned int getConnectWaitDuration(const std::string &uri_)=0
Returns the time that the client should delay before connecting to the given server URI.