DEV Community

Yaroslav Polyakov
Yaroslav Polyakov

Posted on

Simple decorator to retry after exception

Typical situation: you have unreliable function, for example, doing HTTP requests and getting exception from time to time. Maybe connection went down temporary or 429 Too Many requests problem, or remote service itself is temporary broken.

One simple decorator solves problem:

import functools

def retry(num_times=1):
    def decorator_repeat(func):
        @functools.wraps(func)
        def wrapper_repeat(*args, **kwargs):
            last_exception = None
            for n in range(num_times):
                try:
                    r = func(*args, **kwargs)
                except Exception as e:
                    last_exception = e
                    # handle exception. log it or just pass
                    print(f"Try #{n} got exception {e}, but we will retry")
                else:
                    return r
            raise last_exception
        return wrapper_repeat
    return decorator_repeat

Enter fullscreen mode Exit fullscreen mode

Lets use it with requests:

import requests

@retry(10)
def myhttp():
    r = requests.get('https://httpbin.org/status/200,500,429')
    r.raise_for_status()
    print(r.status_code)

myhttp()
Enter fullscreen mode Exit fullscreen mode

Results:

Try #0 got exception 429 Client Error: TOO MANY REQUESTS for url: https://httpbin.org/status/200,500,429, but we will retry
Try #1 got exception 500 Server Error: INTERNAL SERVER ERROR for url: https://httpbin.org/status/200,500,429, but we will retry
Try #2 got exception 500 Server Error: INTERNAL SERVER ERROR for url: https://httpbin.org/status/200,500,429, but we will retry
200
Enter fullscreen mode Exit fullscreen mode

This way you are immune against temporary problems which could be solved by retry (maybe with time.sleep(10)) but you will still get exception from long-time problems. Change URL in myhttp() to https://httpbin.org/status/500 to see this.

Top comments (0)