composer icon indicating copy to clipboard operation
composer copied to clipboard

Add ChunkedEncodingError exception handling for OCI

Open b-chu opened this issue 1 year ago • 1 comments
trafficstars

What does this PR do?

OCI doesn't properly handle their exception oci._vendor.requests.exceptions.ChunkedEncodingError. This means that no retries happen following their default retry strategy. The issue is that they have two subclasses of the same base class, but attempt to compare the subclasses. This fix should be upstreamed to OCI, but this patch allows us to use retries while they work on the fix.

Tested with this script

from circuitbreaker import CircuitBreakerError
from oci._vendor.requests.exceptions import RequestException as BaseRequestException
from oci._vendor.requests.exceptions import Timeout
from oci._vendor.requests.exceptions import ConnectionError as RequestsConnectionError
from oci.exceptions import ServiceError, RequestException, ConnectTimeout
import threading


def should_retry(self, exception=None, response=None, **kwargs):
    if isinstance(exception, Timeout):
        return True
    elif isinstance(exception, RequestsConnectionError):
        return True
    elif isinstance(exception, RequestException):
        return True
    elif isinstance(exception, BaseRequestException):
        return True
    elif isinstance(exception, ConnectTimeout):
        return True
    elif isinstance(exception, CircuitBreakerError):
        if 'circuit_breaker_callback' in kwargs:
            threading.Thread(target=kwargs['circuit_breaker_callback'],
                             args=(exception, )).start()
        return True
    elif isinstance(exception, ServiceError):
        if exception.status in self.service_error_retry_config:
            codes = self.service_error_retry_config[exception.status]
            if not codes:
                return True
            else:
                return exception.code in codes
        elif self.retry_any_5xx and exception.status >= 500 and exception.status != 501:
            return True
    else:
        # This is inside a try block because ConnectionError exists in Python 3 and not in Python 2
        try:
            if isinstance(exception, ConnectionError):
                return True
        except NameError:
            pass

    return False


import oci

oci.retry.retry_checkers.TimeoutConnectionAndServiceErrorRetryChecker.should_retry = should_retry
retry_strategy = oci.retry.DEFAULT_RETRY_STRATEGY
print(
    retry_strategy.checkers.should_retry(
        exception=oci._vendor.requests.exceptions.ChunkedEncodingError()))

What issue(s) does this change relate to?

Before submitting

  • [ ] Have you read the contributor guidelines?
  • [ ] Is this change a documentation change or typo fix? If so, skip the rest of this checklist.
  • [ ] Was this change discussed/approved in a GitHub issue first? It is much more likely to be merged if so.
  • [ ] Did you update any related docs and document your change?
  • [ ] Did you update any related tests and add any new tests related to your change? (see testing)
  • [ ] Did you run the tests locally to make sure they pass?
  • [ ] Did you run pre-commit on your change? (see the pre-commit section of prerequisites)

b-chu avatar Mar 21 '24 19:03 b-chu