def retry(retries=4, delay_multiplier=3, backoff=2):
    def retry_decorator(f):
        @wraps(f)
        def f_retry(*args, **kwargs):
            if retries < 0:
                raise ValueError('retries must be at least 0')
            if delay_multiplier <= 0:
                raise ValueError('delay_multiplier must be larger than 0')
            if backoff <= 1:
                raise ValueError('backoff must be greater than 1')
            mtries, mdelay = retries, delay_multiplier
            while mtries > 1:
                try:
                    return f(*args, **kwargs)
                except SystemExit:
                    msg = "Retrying in {0} seconds...".format(mdelay)
                    lgr.warning(msg)
                    time.sleep(mdelay)
                    mtries -= 1
                    mdelay *= backoff
            return f(*args, **kwargs)
        return f_retry
    return retry_decorator


# # utils.execute(sh.ls, 3, 2, [0], '/var/log')
# def execute(func, attempts=1, sleep=3, accepted_err_codes=[0], *args):
#     if attempts < 1:
#         raise RuntimeError('Attempts must be at least 1')
#     if not sleep > 0:
#         raise RuntimeError('Sleep must be larger than 0')

#     for execution in xrange(attempts):
#         outcome = func(*args, _ok_code=accepted_err_codes)
#         if outcome.exit_code not in accepted_err_codes:
#             lgr.warning('Failed to execute: {0}'.format(func))
#             time.sleep(sleep)
#         else:
#             return outcome
#     lgr.error('Failed to run command even after {0} attempts'
#               ' with output: {1}'.format(execution, outcome))
#     sys.exit(codes.mapping['failed_to_execute_command'])
Retry calling the decorated function using an exponential backoff.
dataset/ETHPy150Open cloudify-cosmo/packman/packman/utils.py/retry