|
|
"""Defines a retry wrapper for io operations.""" |
|
|
|
|
|
import time |
|
|
from functools import wraps |
|
|
|
|
|
|
|
|
def use_backoff(max_retries=2, initial_delay=1, backoff_factor=2): |
|
|
""" |
|
|
Universal retry wrapper with exponential backoff for any function, but primarily for loading |
|
|
and storing HuggingFace datasets and objects. |
|
|
|
|
|
Example usage: |
|
|
|
|
|
>>> @use_backoff(max_retries=10, delay=1, backoff_factor=2) |
|
|
>>> def important_io_operation(x): |
|
|
>>> return x + 1 |
|
|
|
|
|
Args: |
|
|
fn: Function to execute |
|
|
max_retries: Maximum number of retry attempts (default: 3) |
|
|
delay: Initial delay between retries in seconds (default: 1) |
|
|
backoff_factor: Multiplier for delay between retries (default: 2) |
|
|
|
|
|
Returns: |
|
|
A wrapper function that will retry the function fn up to max_retries times with exponential backoff |
|
|
|
|
|
Raises: |
|
|
Exception: If all retries fail |
|
|
""" |
|
|
|
|
|
def _decorator(fn): |
|
|
@wraps(fn) |
|
|
def wrapper(*args, **kwargs): |
|
|
current_delay = initial_delay |
|
|
last_exception = None |
|
|
|
|
|
for attempt in range(max_retries): |
|
|
try: |
|
|
return fn(*args, **kwargs) |
|
|
except Exception as e: |
|
|
last_exception = e |
|
|
if attempt < max_retries - 1: |
|
|
time.sleep(current_delay) |
|
|
current_delay *= backoff_factor |
|
|
|
|
|
raise Exception( |
|
|
f"IO Operation failed after {max_retries} attempts: {str(last_exception)}" |
|
|
) |
|
|
|
|
|
return wrapper |
|
|
|
|
|
return _decorator |
|
|
|