o
    ɶd!                     @   s   d dl mZmZmZ ddlmZ ddlmZ ddlmZ	 ddl
Z
ddlZe
eZg dgg dZG d	d
 d
eZG dd deZG dd deZG dd deZG dd deZdS )   )ServiceErrorRequestExceptionConnectTimeout    )CircuitBreakerError)Timeout)ConnectionErrorNIncorrectStatei  i  c                   @   s*   e Zd ZdZdd Zdd Zd	ddZdS )
RetryCheckerContainera  
    A container which holds at least one retry checker. This lets us chain together different retry checkers into an overall
    evaluation of whether we should retry a request.

    Checkers are evaluated in the order they appear in the provided list of checkers, and if one checker reports failure we
    consider this to be an overall failure and no more retries should happen.
    c                 K   s   |st d|| _d S )Nz/At least one retry checker needs to be provided)
ValueErrorcheckers)selfr   kwargs r   <usr/lib/python3.10/site-packages/oci/retry/retry_checkers.py__init__!   s   
zRetryCheckerContainer.__init__c                 C   s   | j | d S N)r   append)r   Zcheckerr   r   r   add_checker&   s   z!RetryCheckerContainer.add_checkerNc                 K   s*   | j D ]}|j||fi |s dS qdS )aE  
        Determines if a retry should be performed based on either an exception or a response. We will
        retry if all the checkers held in this container indicate that they should retry; if any checker
        indicates that the call should not be retried then we will not retry.

        :param Exception exception:
            An exception received from the service

        :param Response response:
            The :class:`~oci.response.Response` received from a service call

        :return: True if we should retry, and False otherwise
        :rtype: Boolean
        FT)r   should_retry)r   	exceptionresponser   cr   r   r   r   )   s
   
z"RetryCheckerContainer.should_retryNN)__name__
__module____qualname____doc__r   r   r   r   r   r   r   r      s
    r   c                   @   s"   e Zd ZdZdd ZdddZdS )BaseRetryCheckerz
    The base class from which all retry checkers should derive. This has no implementation but just defines the contract
    for a checker. Implementors can extend this class to define their own checking logic.
    c                 K   s   d S r   r   )r   r   r   r   r   r   E   s   zBaseRetryChecker.__init__Nc                 K   s   t d)a  
        Determines if a retry should be performed based on either an exception or a response.

        :param Exception exception:
            An exception received from the service

        :param Response response:
            The :class:`~oci.response.Response` received from a service call

        :return: True if we should retry, and False otherwise
        :rtype: Boolean
        z Subclasses should implement this)NotImplementedErrorr   r   r   r   r   r   r   r   H   s   zBaseRetryChecker.should_retryr   )r   r   r   r   r   r   r   r   r   r   r    ?   s    r    c                       ,   e Zd ZdZd fdd	Zd	ddZ  ZS )
TotalTimeExceededRetryCheckeraz  
    A retry checker which can retry as long as some upper time limit (in seconds) has not been breached. This is intended
    for scenarios such as "keep retrying for 5 minutes". It is the responsiblity of the caller to track the total time
    elapsed - objects of this class will not track this.

    If not specified, the default time limit is 600 seconds (10 minutes).
    X  c                    s    t t| jdi | || _d S Nr   )superr$   r   time_limit_seconds)r   r(   r   	__class__r   r   r   a   s   
z&TotalTimeExceededRetryChecker.__init__Nc                 K      | j |ddkS )NZtotal_time_elapsedr   )r(   getr"   r   r   r   r   e      z*TotalTimeExceededRetryChecker.should_retry)r%   r   r   r   r   r   r   r   __classcell__r   r   r)   r   r$   X   s    r$   c                       r#   )
LimitBasedRetryCheckera  
    A retry checker which can retry as long as some threshold (# of attempts/tries) has not been breached.
    It is the responsiblity of the caller to track how many attempts/tries it has done - objects of this
    class will not track this.

    If not specified, the default number of tries allowed is 8. Tries are also assumed to be one-based (i.e. the
    first attempt/try is 1, the second is 2 etc)
       c                    s0   |dk rt dtt| jdi | || _d S )N   zEThe max number of attempts must be >= 1, with 1 indicating no retriesr   )r   r'   r0   r   max_attempts)r   r3   r   r)   r   r   r   s   s   
zLimitBasedRetryChecker.__init__Nc                 K   r+   )NZcurrent_attemptr   )r3   r,   r"   r   r   r   r   z   r-   z#LimitBasedRetryChecker.should_retry)r1   r   r.   r   r   r)   r   r0   i   s    	r0   c                       s>   e Zd ZdZg dgg dZedf fdd	Zd
dd	Z  ZS ),TimeoutConnectionAndServiceErrorRetryCheckera  
    A checker which will retry on certain exceptions. Retries are enabled for the following exception types:

        - Timeouts from the requests library (we will always retry on these)
        - ConnectionErrors from the requests library (we will always retry on these)
        - Built-in ConnectionErrors from Python 3
        - Service errors where the status is 500 or above (i.e. a server-side error, except 501)
        - Service errors where a status (e.g. 429) and, optionally, the code meet a given criteria

    The last item is configurable via dictionary where the key is some numeric status representing a HTTP status and the value
    is a list of strings with each string representing a textual error code (such as those error codes documented at
    https://docs.cloud.oracle.com/Content/API/References/apierrors.htm). If an empty list is provided, then
    only the numeric status is checked for retry purposes. For a populated array, we are looking for where the numeric status matches
    and the code from the exception appears in the array. As an example:

    .. code-block:: python

        {
            400: ['QuotaExceeded'],
            500: []
        }

    If no configuration is provided, then the default for service errors is to retry on HTTP 409/IncorrectState, 429's and 5xx's (except 501) without any
    code checks. If a specific 5xx code (e.g. 500, 502) is provided in the dictionary, then it takes precedence over the option to retry on any 500, for example,
    it is possible to retry on only 502s (either by status or by status and matching some code) by disabling the general "retry on any 5xx"
    configuration and placing an entry for 502 in the dictionary
    r	   r
   Tc                    s&   t t| jdi | || _|| _d S r&   )r'   r4   r   retry_any_5xxservice_error_retry_config)r   r6   r5   r   r)   r   r   r      s   
z5TimeoutConnectionAndServiceErrorRetryChecker.__init__Nc                 K   s   t |trdS t |trdS t |trdS t |trdS t |tr3d|v r1tj|d |fd  dS t |t	r^|j
| jv rM| j|j
 }|sHdS |j|v S | jr\|j
dkr\|j
dkr\dS dS zt |trgW dS W dS  tys   Y dS w )NTZcircuit_breaker_callback)targetargsi  i  F)
isinstancer   RequestsConnectionErrorr   r   r   	threadingThreadstartr   statusr6   coder5   r   	NameError)r   r   r   r   codesr   r   r   r      s<   






	
z9TimeoutConnectionAndServiceErrorRetryChecker.should_retryr   )r   r   r   r   RETRYABLE_STATUSES_AND_CODESr   r   r/   r   r   r)   r   r4   ~   s    r4   )
exceptionsr   r   r   Zcircuitbreakerr   Zoci._vendor.requests.exceptionsr   r   r:   loggingr;   	getLoggerr   loggerrB   objectr   r    r$   r0   r4   r   r   r   r   <module>   s    
'