6

let's say I have the following function:

@retry(stop=stop_after_attempt(3))
def foo():
  try:
    response = requests.post(...)
    response.raise_for_status()
    return response
  except Exception as e:
    raise e

This function will retry 3 times, and if all three retries fail, an exception will be raised.

How can I use tenacity to do 3 retries without raising the exception? Something like:

@retry(stop=stop_after_attempt(3))
def foo(ignore_errors=False):
  try:
    response = requests.post(...)
    response.raise_for_status()
    return response
  except Exception as e:
    if ignore_errors and function has been retried three times:
      pass
    raise e
JTa
  • 181
  • 1
  • 12
  • Just remove `raise`, and replace it with something like `print("Oh my god, there was an error, call the fire department!")`. – Mooncrater Sep 30 '20 at 07:42
  • 4
    But if I don't raise the error in the exception, how will it trigger the retries? – JTa Oct 08 '20 at 17:16

3 Answers3

8

The retry decorator has a retry_error_callback argument that can override the default behavior of raising a RetryError if all retries fail. This argument is expected to be a function that accepts one argument, called retry_state, and if you return a value from this function, that value will be returned by the function if all retries fail.

An example:

from tenacity import retry, stop_after_attempt

return_value_on_error = "something"

@retry(
    stop=stop_after_attempt(3),
    retry_error_callback=lambda retry_state: return_value_on_error,
)
def broken_function():
    raise RuntimeError

assert broken_function() == return_value_on_error
b-r-oleary
  • 116
  • 1
  • 3
  • 1
    what if i want to call a specific function with argument when all attempts failed? any way to do that? – nadeem Jan 08 '23 at 14:21
  • @nadeem Yes, the `retry_state` object that is passed into the `retry_error_callback` function contains the arguments to the function that is being retried in the `retry_state.args` and `retry_state.kwargs` properties. So, by using those properties, you can call a function that depends on arguments passed to the function after all attempts failed. – b-r-oleary Jan 10 '23 at 21:39
0

It's recommended to control exception outside of foo function.

try:
    foo()
except Exception as e:
    print("foo fails with retry: {e}")
정도유
  • 559
  • 4
  • 6
-5

Using pure python:

def foo(tries=0,maxTries=3):
    try:
        response = requests.post(...)
        response.raise_for_status()
        return response
    except Exception as e:
        if tries>=maxTries:
            print("Maxtries reached.")
            return
        else:
            foo(tries+1,maxTries)

I'm not sure if a recursive function would help here.

Mooncrater
  • 4,146
  • 4
  • 33
  • 62