Revision c7d3a832
b/lib/utils/retry.py | ||
---|---|---|
182 | 182 |
current_delay = calc_delay() |
183 | 183 |
if current_delay > 0.0: |
184 | 184 |
wait_fn(current_delay) |
185 |
|
|
186 |
|
|
187 |
def SimpleRetry(expected, fn, delay, timeout, args=None, wait_fn=time.sleep, |
|
188 |
_time_fn=time.time): |
|
189 |
"""A wrapper over L{Retry} implementing a simpler interface. |
|
190 |
|
|
191 |
All the parameters are the same as for L{Retry}, except it has one |
|
192 |
extra argument: expected, which can be either a value (will be |
|
193 |
compared with the result of the function, or a callable (which will |
|
194 |
get the result passed and has to return a boolean). If the test is |
|
195 |
false, we will retry until either the timeout has passed or the |
|
196 |
tests succeeds. In both cases, the last result from calling the |
|
197 |
function will be returned. |
|
198 |
|
|
199 |
Note that this function is not expected to raise any retry-related |
|
200 |
exceptions, always simply returning values. As such, the function is |
|
201 |
designed to allow easy wrapping of code that doesn't use retry at |
|
202 |
all (e.g. "if fn(args)" replaced with "if SimpleRetry(True, fn, |
|
203 |
...)". |
|
204 |
|
|
205 |
@see: L{Retry} |
|
206 |
|
|
207 |
""" |
|
208 |
rdict = {} |
|
209 |
def helper(*innerargs): |
|
210 |
# pylint: disable-msg=W0142 |
|
211 |
result = rdict["result"] = fn(*innerargs) |
|
212 |
if not ((callable(expected) and expected(result)) or result == expected): |
|
213 |
raise RetryAgain() |
|
214 |
return result |
|
215 |
|
|
216 |
try: |
|
217 |
result = Retry(helper, delay, timeout, args=args, |
|
218 |
wait_fn=wait_fn, _time_fn=_time_fn) |
|
219 |
except RetryTimeout: |
|
220 |
assert "result" in rdict |
|
221 |
result = rdict["result"] |
|
222 |
return result |
b/test/ganeti.utils.retry_unittest.py | ||
---|---|---|
34 | 34 |
def setUp(self): |
35 | 35 |
testutils.GanetiTestCase.setUp(self) |
36 | 36 |
self.retries = 0 |
37 |
self.called = 0 |
|
37 | 38 |
|
38 | 39 |
@staticmethod |
39 | 40 |
def _RaiseRetryAgain(): |
... | ... | |
53 | 54 |
else: |
54 | 55 |
return True |
55 | 56 |
|
57 |
def _SimpleRetryAndSucceed(self, retries): |
|
58 |
self.called += 1 |
|
59 |
if self.retries < retries: |
|
60 |
self.retries += 1 |
|
61 |
return False |
|
62 |
else: |
|
63 |
return True |
|
64 |
|
|
56 | 65 |
def testRaiseTimeout(self): |
57 | 66 |
self.failUnlessRaises(utils.RetryTimeout, utils.Retry, |
58 | 67 |
self._RaiseRetryAgain, 0.01, 0.02) |
... | ... | |
112 | 121 |
else: |
113 | 122 |
self.fail("Expected RetryTimeout didn't happen") |
114 | 123 |
|
124 |
def testSimpleRetry(self): |
|
125 |
self.assertFalse(utils.SimpleRetry(True, lambda: False, 0.01, 0.02)) |
|
126 |
self.assertFalse(utils.SimpleRetry(lambda x: x, lambda: False, 0.01, 0.02)) |
|
127 |
self.assertTrue(utils.SimpleRetry(True, lambda: True, 0, 1)) |
|
128 |
self.assertTrue(utils.SimpleRetry(lambda x: x, lambda: True, 0, 1)) |
|
129 |
self.assertTrue(utils.SimpleRetry(True, self._SimpleRetryAndSucceed, |
|
130 |
0, 1, args=[1])) |
|
131 |
self.assertEqual(self.retries, 1) |
|
132 |
self.assertEqual(self.called, 2) |
|
133 |
self.called = self.retries = 0 |
|
134 |
self.assertTrue(utils.SimpleRetry(True, self._SimpleRetryAndSucceed, |
|
135 |
0, 1, args=[2])) |
|
136 |
self.assertEqual(self.called, 3) |
|
137 |
|
|
115 | 138 |
|
116 | 139 |
if __name__ == "__main__": |
117 | 140 |
testutils.GanetiTestProgram() |
Also available in: Unified diff