Hyrex provides automatic retry mechanisms for tasks that fail due to transient errors. Configure retries using max_retries and retry_backoff parameters.

Basic Retries

Set max_retries to automatically retry failed tasks:
from hyrex import HyrexRegistry

hy = HyrexRegistry()

@hy.task(max_retries=3)
def flaky_api_call():
    response = requests.get("https://api.example.com")
    if response.status_code >= 500:
        # Raising an exception triggers a retry
        raise Exception("Server error")
    return response.json()
Any unhandled exception will trigger a retry. To prevent retries for specific errors, catch the exception and return an error response instead.

Backoff Strategies

Fixed Backoff

@hy.task(
    max_retries=3,
    retry_backoff=10  # 10 seconds between retries
)
def fixed_backoff_task():
    pass

Exponential Backoff

@hy.task(
    max_retries=5,
    retry_backoff=lambda attempt: 2 ** attempt
)
def exponential_task():
    # Delays: 2s, 4s, 8s, 16s, 32s
    pass

Custom Backoff

def custom_backoff(attempt: int) -> int:
    base = 5 * attempt
    jitter = random.randint(0, 5)
    return min(base + jitter, 300)  # Max 5 minutes

@hy.task(
    max_retries=5,
    retry_backoff=custom_backoff
)
def custom_task():
    pass

Error Handlers

Use on_error callbacks to monitor failures without affecting retry behavior:
from hyrex import get_hyrex_context

def handle_error(error: Exception):
    context = get_hyrex_context()
    
    if context:
        # Log error with context
        print(f"Task {context.task_name} failed on attempt {context.attempt_number}: {error}")
        
        # Alert on final retry
        if context.attempt_number == context.max_retries:
            send_alert(f"Task {context.task_name} failed after {context.max_retries} attempts")

@hy.task(
    max_retries=3,
    on_error=handle_error
)
def monitored_task(data: dict):
    # Task logic that might fail
    process_data(data)
The on_error handler must accept either no arguments or exactly one Exception argument. The handler runs after each failure but doesn’t prevent retries.

Retry Context

Access retry information within tasks:
@hy.task(max_retries=3)
def adaptive_task():
    context = get_hyrex_context()
    
    if context:
        # Different behavior based on attempt
        if context.attempt_number == 1:
            timeout = 5
        elif context.attempt_number == 2:
            timeout = 10
        else:
            timeout = 30
        
        print(f"Attempt {context.attempt_number} of {context.max_retries + 1}")
    else:
        timeout = 5
    
    return fetch_with_timeout(timeout)

Selective Retry Behavior

Control which errors trigger retries:
class PermanentError(Exception):
    """Errors that should not be retried"""
    pass

@hy.task(max_retries=3)
def selective_retry_task(url: str):
    try:
        response = requests.get(url)
        
        if response.status_code == 404:
            # Don't retry - return error result
            return {"error": "Not found", "status": 404}
        
        if response.status_code == 400:
            # Don't retry - catch and return
            raise PermanentError("Bad request")
            
        if response.status_code >= 500:
            # Do retry - let exception propagate
            raise Exception(f"Server error: {response.status_code}")
            
        return response.json()
        
    except PermanentError as e:
        # Catch permanent errors to prevent retry
        return {"error": str(e), "permanent": True}
    # Let other exceptions propagate for retry

Next Steps