def _retry_with_backoff(operation_name, func, max_retries=MAX_RETRIES, retry_codes=None):
    """Execute a function with exponential backoff retry logic.

    Args:
        operation_name: Name of the operation for error messages
        func: Function to execute that returns (success, result)
        max_retries: Maximum number of retry attempts

    Returns:
        The result from the function if successful

    Raises:
        DbtException: If all retry attempts fail
    """
    if retry_codes is None:
        retry_codes = [500, 502, 503, 504]
    retry_delay = 1
    for attempt in range(max_retries + 1):
        try:
            success, result = func()
            if success:
                return result

            if result.status_code not in retry_codes:
                raise DbtException(f"Error {operation_name}: {result}")
            if attempt == max_retries:  # Last attempt
                raise DbtException(f"Error {operation_name}: {result}")
        except requests.RequestException as e:
            if attempt == max_retries:  # Last attempt
                raise DbtException(f"Error {operation_name}: {str(e)}")

        time.sleep(retry_delay)
        retry_delay *= 2  # exponential backoff
Execute a function with exponential backoff retry logic.

    Args:
        operation_name: Name of the operation for error messages
        func: Function to execute that returns (success, result)
        max_retries: Maximum number of retry attempts

    Returns:
        The result from the function if successful

    Raises:
        DbtException: If all retry attempts fail
    
core/dbt/utils/artifact_upload.py