# The implementation of the retry logic
def retry(
    callback: Callable[[], Response],
    config: Optional[RetryConfig] = None,
) -> Response:
    """
    Retries the given callback based on the retry configuration.
    """
    if config is None or config.strategy != "backoff" or config.backoff is None:
        return callback()

    retry_attempt = 0
    status_codes = _parse_status_codes(config.status_codes)

    while True:
        try:
            response = callback()

            # Check if we should retry based on the status code
            if response.status_code in status_codes:
                if retry_attempt >= config.backoff.max_retries:
                    return response

                _sleep_with_jitter(config.backoff, retry_attempt)
                retry_attempt += 1
                continue

            return response

        except requests.exceptions.ConnectionError as e:
            if not config.retry_connection_errors or retry_attempt >= config.backoff.max_retries:
                raise e

            _sleep_with_jitter(config.backoff, retry_attempt)
            retry_attempt += 1
```

This retry logic directly reflects the configuration you provided in the `x-speakeasy-retries` extension in your OpenAPI document, ensuring consistent behavior between your API documentation and the generated SDK.


## Summary

In this guide, we showed you how to generate an OpenAPI document for a Django API and use Speakeasy to create an SDK based on the OpenAPI document. The step-by-step instructions included adding relevant tools to the Django project, generating an OpenAPI document, enhancing it for improved creation, using Speakeasy OpenAPI extensions, and interpreting the basics of the generated SDK.

We also explored automating SDK generation through CI/CD workflows and improving API operations.