Merge pull request #40 from cyrusd/master

Callbacks for before/after attempts
This commit is contained in:
Ray Holder 2016-06-05 22:21:29 -05:00
commit 855db168d3
4 changed files with 49 additions and 3 deletions

3
.gitignore vendored
View File

@ -1,4 +1,5 @@
.idea
dist
*.pyc
*.egg-info
*.egg-info
build

View File

@ -30,4 +30,5 @@ Patches and Suggestions
- Monty Taylor
- Maxym Shalenyi
- Jonathan Herriott
- Job Evers
- Job Evers
- Cyrus Durgin

View File

@ -69,7 +69,9 @@ class Retrying(object):
wrap_exception=False,
stop_func=None,
wait_func=None,
wait_jitter_max=None):
wait_jitter_max=None,
before_attempts=None,
after_attempts=None):
self._stop_max_attempt_number = 5 if stop_max_attempt_number is None else stop_max_attempt_number
self._stop_max_delay = 100 if stop_max_delay is None else stop_max_delay
@ -82,6 +84,8 @@ class Retrying(object):
self._wait_exponential_max = MAX_WAIT if wait_exponential_max is None else wait_exponential_max
self._wait_incrementing_max = MAX_WAIT if wait_incrementing_max is None else wait_incrementing_max
self._wait_jitter_max = 0 if wait_jitter_max is None else wait_jitter_max
self._before_attempts = before_attempts
self._after_attempts = after_attempts
# TODO add chaining of stop behaviors
# stop behavior
@ -203,6 +207,9 @@ class Retrying(object):
start_time = int(round(time.time() * 1000))
attempt_number = 1
while True:
if self._before_attempts:
self._before_attempts(attempt_number)
try:
attempt = Attempt(fn(*args, **kwargs), attempt_number, False)
except:
@ -212,6 +219,9 @@ class Retrying(object):
if not self.should_reject(attempt):
return attempt.get(self._wrap_exception)
if self._after_attempts:
self._after_attempts(attempt_number)
delay_since_first_attempt_ms = int(round(time.time() * 1000)) - start_time
if self.stop(attempt_number, delay_since_first_attempt_ms):
if not self._wrap_exception and attempt.has_exception:

View File

@ -434,5 +434,39 @@ class TestDecoratorWrapper(unittest.TestCase):
self.assertTrue(_retryable_default(NoCustomErrorAfterCount(5)))
self.assertTrue(_retryable_default_f(NoCustomErrorAfterCount(5)))
class TestBeforeAfterAttempts(unittest.TestCase):
_attempt_number = 0
def test_before_attempts(self):
TestBeforeAfterAttempts._attempt_number = 0
def _before(attempt_number):
TestBeforeAfterAttempts._attempt_number = attempt_number
@retry(wait_fixed = 1000, stop_max_attempt_number = 1, before_attempts = _before)
def _test_before():
pass
_test_before()
self.assertTrue(TestBeforeAfterAttempts._attempt_number is 1)
def test_after_attempts(self):
TestBeforeAfterAttempts._attempt_number = 0
def _after(attempt_number):
TestBeforeAfterAttempts._attempt_number = attempt_number
@retry(wait_fixed = 100, stop_max_attempt_number = 3, after_attempts = _after)
def _test_after():
if TestBeforeAfterAttempts._attempt_number < 2:
raise Exception("testing after_attempts handler")
else:
pass
_test_after()
self.assertTrue(TestBeforeAfterAttempts._attempt_number is 2)
if __name__ == '__main__':
unittest.main()