Skip to content
This repository was archived by the owner on Aug 8, 2025. It is now read-only.

Commit e105de7

Browse files
authored
Merge pull request #13 from bgreen-litl/giveup_kwarg
Add giveup kwarg for exception inspection
2 parents 787f678 + cc8dc94 commit e105de7

File tree

3 files changed

+45
-3
lines changed

3 files changed

+45
-3
lines changed

README.rst

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,23 @@ you want the same backoff behavior for more than one exception type::
4646
def get_url(url):
4747
return requests.get(url)
4848

49+
In some cases the raised exception instance itself may need to be
50+
inspected in order to determine if it is a retryable condition. The
51+
``giveup`` keyword arg can be used to specify a function which accepts
52+
the exception and returns a truthy value if the exception should not
53+
be retried::
54+
55+
def fatal_code(e):
56+
return 400 <= e.response.status_code < 500
57+
58+
@backoff.on_exception(backoff.expo,
59+
requests.exceptions.RequestException,
60+
max_tries=8,
61+
giveup=fatal_code)
62+
def get_url(url):
63+
return requests.get(url)
64+
65+
4966
@backoff.on_predicate
5067
---------------------
5168

backoff.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ def retry(*args, **kwargs):
165165
tries += 1
166166
ret = target(*args, **kwargs)
167167
if predicate(ret):
168-
if max_tries is not None and tries == max_tries:
168+
if tries == max_tries:
169169
for hdlr in giveup_hdlrs:
170170
hdlr({'target': target,
171171
'args': args,
@@ -216,6 +216,7 @@ def on_exception(wait_gen,
216216
exception,
217217
max_tries=None,
218218
jitter=full_jitter,
219+
giveup=lambda e: False,
219220
on_success=None,
220221
on_backoff=None,
221222
on_giveup=None,
@@ -237,6 +238,9 @@ def on_exception(wait_gen,
237238
concurrent clients. Wait times are jittered by default
238239
using the full_jitter function. Jittering may be disabled
239240
altogether by passing jitter=None.
241+
giveup: Function accepting an exception instance and
242+
returning whether or not to give up. Optional. The default
243+
is to always continue.
240244
on_success: Callable (or iterable of callables) with a unary
241245
signature to be called in the event of success. The
242246
parameter is a dict containing details about the invocation.
@@ -265,8 +269,9 @@ def retry(*args, **kwargs):
265269
try:
266270
tries += 1
267271
ret = target(*args, **kwargs)
268-
except exception:
269-
if max_tries is not None and tries == max_tries:
272+
except exception as e:
273+
if giveup(e) or tries == max_tries:
274+
270275
for hdlr in giveup_hdlrs:
271276
hdlr({'target': target,
272277
'args': args,

backoff_tests.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,26 @@ def exceptor(*args, **kwargs):
316316
'tries': 3}
317317

318318

319+
def test_on_exception_giveup_predicate(monkeypatch):
320+
monkeypatch.setattr('time.sleep', lambda x: None)
321+
322+
def on_baz(e):
323+
return str(e) == "baz"
324+
325+
vals = ["baz", "bar", "foo"]
326+
327+
@backoff.on_exception(backoff.constant,
328+
ValueError,
329+
giveup=on_baz)
330+
def foo_bar_baz():
331+
raise ValueError(vals.pop())
332+
333+
with pytest.raises(ValueError):
334+
foo_bar_baz()
335+
336+
assert not vals
337+
338+
319339
def test_on_predicate_success():
320340
log, log_success, log_backoff, log_giveup = _log_hdlrs()
321341

0 commit comments

Comments
 (0)