o
    ɶdf                     @   s   d dl mZ ddlmZ ddlmZ ddlmZmZmZ ddl	Z	dZ
d	Zd
ZdZe
eeeg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G dd deZG dd deZdS )   )ServiceError   )retry_checkers)retry_sleep_utils    )%should_record_body_position_for_retryrecord_body_position_for_rewindrewind_bodyNZfull_jitterZequal_jitterZ"full_jitter_with_equal_on_throttledecorrelated_jitterc                   @   sT   e Zd ZdZdd ZdddZdd Zdd
dZdd Zdd Z	dd Z
dd ZdS )RetryStrategyBuildera  
    A class which can build a retry strategy based on provided criteria. Criteria can be provided at construction time or
    afterwards via using the ``add_*`` (to add/enable criteria) and ``no_*`` (to disable/remove criteria) methods.

    Trying to build a strategy when there are no enabled checks will result in a :py:class:`oci.retry.NoneRetryStrategy`
    being produced.

    This builder is intended as a convenience, but callers are also able to bypass this and construct retry strategies
    directly.
    c                 K   s   | dd| _| dd| _| dd| _| dd| _| dd| _| d	tj| _| d
d| _	| dd| _
| dd| _| dd| _| dd| _t| _d|v ri|d tvrbtdt|d | _dS dS )a  
        Creates a new builder and initializes it based on any provided parameters.

        :param Boolean max_attempts_check (optional):
            Whether to enable a check that we don't exceed a certain number of attempts. If not provided
            this defaults to True (with a default max-attempts = 8)

        :param Boolean service_error_check (optional):
            Whether to enable a check that will retry on connection errors, timeouts and service errors
            which match given combinations of HTTP statuses and textual error codes. If not provided
            this defaults to True (i.e. this check will be done)

        :param Boolean total_elapsed_time_check (optional):
            Whether to enable a check that we don't exceed a certain amount of time when retrying. This is intended
            for scenarios such as "keep retrying for 5 minutes".  If not provided this defaults to True
            (i.e. this check will be done with the total elapsed time of 600 seconds)

        :param int max_attempts (optional):
            If we are checking that we don't exceed a certain number of attempts, what that number of
            attempts should be. This only applies if we are performing a check on the maximum number of
            attempts and will be ignored otherwise. If we are performing a check on the maximum number of
            attempts and this value is not provided, we will default to a maximum of 8 attempts

        :param int total_elapsed_time_seconds (optional):
            If we are checking that we don't exceed a certain amount of time when retrying, what that amount of
            time should be (in seconds). This only applies if we are performing a check on the total elapsed time and will
            be ignored otherwise. If we are performing a check on the total elapsed time and this value is not provided, we
            will default to 600 seconds (10 minutes)

        :param dict service_error_retry_config (optional):
            If we are checking on service errors, we can configure what HTTP statuses (e.g. 429) to retry on and, optionally,
            whether the textual code (e.g. TooManyRequests) matches a given value.

            This is a dictionary where the key is an integer representing the HTTP status, and the value is a list(str) where we
            will test if the textual code in the service error is a member of the list. If an empty list is provided, then only
            the numeric status is checked for retry purposes.

            If we are performing a check on service errors and this value is not provided, then by default we will retry on
            HTTP 409/IncorrectState, 429's (throttles) without any textual code check.

        :param Boolean service_error_retry_on_any_5xx (optional):
            If we are checking on service errors, whether to retry on any HTTP 5xx received from the service. If
            we are performing a check on service errors and this value is not provided, it defaults to True (retry on any 5xx except 501)

        :param int retry_base_sleep_time_seconds (optional):
            For exponential backoff with jitter, the base time to use in our retry calculation in seconds. If not
            provided, this value defaults to 1 second

        :param int retry_exponential_growth_factor (optional):
            For exponential backoff with jitter, the exponent which we will raise to the power of the number of attempts. If
            not provided, this value defaults to 2

        :param int retry_max_wait_between_calls_seconds (optional):
            For exponential backoff with jitter, the maximum amount of time to wait between retries. If not provided, this
            value defaults to 30 seconds

        :param int decorrelated_jitter (optional):
            The random De-correlated jitter value in seconds (default 1) to be used when using the backoff_type BACKOFF_DECORRELATED_JITTER_VALUE

        :param str backoff_type (optional):
            The type of backoff we want to do (e.g. full jitter). The convenience constants in this retry module: ``BACKOFF_DECORRELATED_JITTER_VALUE``,
            ``BACKOFF_FULL_JITTER_VALUE``,`BACKOFF_EQUAL_JITTER_VALUE``, and ``BACKOFF_FULL_JITTER_EQUAL_ON_THROTTLE_VALUE`` can be used as values here.
            If no value is specified then the value ``BACKOFF_DECORRELATED_JITTER_VALUE`` will be used. This will use exponential backoff and a
            random de-correlated jitter.
        max_attempts_checkTservice_error_checktotal_elapsed_time_checkmax_attempts   total_elapsed_time_secondsX  service_error_retry_configservice_error_retry_on_any_5xxretry_base_sleep_time_secondsr   retry_exponential_growth_factorr   $retry_max_wait_between_calls_seconds   r
   backoff_typez<Unrecognized backoff type supplied. Recognized types are: {}N)getr   r   r   r   r   r   ZRETRYABLE_STATUSES_AND_CODESr   r   r   r   r   r
   !BACKOFF_DECORRELATED_JITTER_VALUEr   VALID_BACKOFF_TYPES
ValueErrorformatselfkwargs r"   3usr/lib/python3.10/site-packages/oci/retry/retry.py__init__"   s"   CzRetryStrategyBuilder.__init__r   c                 C      d| _ |r|| _| S NT)r   r   )r    r   r"   r"   r#   add_max_attemptsz      z%RetryStrategyBuilder.add_max_attemptsc                 C   
   d| _ | S NF)r   r    r"   r"   r#   no_max_attemps      z#RetryStrategyBuilder.no_max_attempsr   c                 C   r%   r&   )r   r   )r    r   r"   r"   r#   add_total_elapsed_time   r(   z+RetryStrategyBuilder.add_total_elapsed_timec                 C   r)   r*   )r   r+   r"   r"   r#   no_total_elapsed_time   r-   z*RetryStrategyBuilder.no_total_elapsed_timec                 K   sR   d| _ d|v r|d | _nd|v rd|v r|d | j|d < d|v r'|d | _| S )NTr   Zservice_error_statusZservice_error_codesr   )r   r   r   r   r"   r"   r#   add_service_error_check   s   
z,RetryStrategyBuilder.add_service_error_checkc                 C   r)   r*   )r   r+   r"   r"   r#   no_service_error_check   r-   z+RetryStrategyBuilder.no_service_error_checkc                 C   sX  | j s| js| jst S g }| j r&| jr|tj| jd n|t  | jrC| jr9|tj	| j| j
d n
|tj	| j
d | jr[| jrT|tj| jd n|t  tj|d}| jtkrst| j| j| j|| jdS | jtkrt| j| j| j|dS | jtkrt| j| j| j|dS | jtkrt| j| j| j|dS td| jt)	N)r   )r   retry_any_5xx)r2   )Ztime_limit_seconds)checkers)base_sleep_time_secondsexponent_growth_factormax_wait_between_calls_secondschecker_containerr
   )r4   r5   r6   r7   z2Unrecognized backoff type: {}. Expected one of: {})r   r   r   NoneRetryStrategyr   appendr   LimitBasedRetryCheckerr   Z,TimeoutConnectionAndServiceErrorRetryCheckerr   r   ZTotalTimeExceededRetryCheckerZRetryCheckerContainerr   r   5ExponentialBackOffWithDecorrelatedJitterRetryStrategyr   r   r   r
   BACKOFF_FULL_JITTER_VALUE-ExponentialBackoffWithFullJitterRetryStrategyBACKOFF_EQUAL_JITTER_VALUE.ExponentialBackoffWithEqualJitterRetryStrategy+BACKOFF_FULL_JITTER_EQUAL_ON_THROTTLE_VALUE>ExponentialBackoffWithFullJitterEqualForThrottlesRetryStrategyr   r   r   )r    r3   r7   r"   r"   r#   get_retry_strategy   sf   



z'RetryStrategyBuilder.get_retry_strategyN)r   )r   )__name__
__module____qualname____doc__r$   r'   r,   r.   r/   r0   r1   rB   r"   r"   r"   r#   r      s    
X
r   c                   @   s   e Zd ZdZdd ZdS )r8   z(
    A strategy that does not retry
    c                 O   s   ||i |S )5  
        Calls the function given by func_ref. Any positional (``*func_args``) and keyword (``**func_kwargs``)
        arguments are passed as-is to func_ref.

        :param function func_ref:
            The function that we should call with retries

        :return: the result of calling func_ref
        r"   )r    func_ref	func_argsfunc_kwargsr"   r"   r#   make_retrying_call   s   
z$NoneRetryStrategy.make_retrying_callN)rC   rD   rE   rF   rK   r"   r"   r"   r#   r8      s    r8   c                   @   s0   e Zd ZdZdd Zdd Zdd Zdd	 Zd
S )#ExponentialBackoffRetryStrategyBasea  
    A base retry strategy from which other retry strategies inherit. Implementors can create a subclass of this to define
    their own retry logic. This is primarily useful when an implementor wishes to customize the sleep strategy used - to
    customize the checking logic on whether a retry should be done, implementors can define their own subclasses of
    :py:class:`oci.retry.retry_checkers.BaseRetryChecker` and provide this in the checker container.
    c                 K   s"   || _ || _|| _|| _d| _dS )a  
        Creates a new instance of an exponential backoff with full jitter retry strategy.

        :param int base_sleep_time_seconds:
            The base amount to sleep by, in seconds

        :param int exponent_growth_factor:
            The exponent part of our backoff. We will raise take this value and raising it to the power
            of attemps and then multiply this with base_sleep_time_seconds

        :param int max_wait_between_calls_seconds:
            The maximum time we will wait between calls, in seconds

        :param retry_checkers.RetryCheckerContainer checker_container:
            The checks to run to determine whether a failed call should be retried
        N)r4   r5   r6   r3   circuit_breaker_callbackr    r4   r5   r6   r7   r!   r"   r"   r#   r$      s
   
z,ExponentialBackoffRetryStrategyBase.__init__c              
   O   s  d}d}ddd}d}t   }t|fi |}	d}
| jj}|D ]}t|tju r+|j}qt|ddrE|j}t|dd|d< t|dd|d< |d r[|d r[|d 	d	
|| j| j |rz-|	rit|d
\}
}||i |}t   | }|d r|d r|d 	d
| |W S  ty } zPt|dd}t|dd}|d7 }|
r| jj||t   | | jdr| || |	r|
rt|d
|sƂ |d r|d r|d 	d
||| n W Y d}~nd}~ww |s]dS dS )rG   TNF)loggerdebugr   __self__rO   rP   z\Retry policy to use: MaximumNumberAttempts={}, MaxSleepBetween={}, ExponentialBackoffBase={}bodyz%Total Latency for this API call is {}statuscoder   )	exceptionZcurrent_attemptZtotal_time_elapsedrM   z7Retry attempt: {}, Http Status Code: {}, Error Code: {})timer   r3   typer   r:   r   getattrrQ   rP   r   r6   r5   r   r   	Exceptionshould_retryrM   do_sleepr	   )r    rH   rI   rJ   rZ   Zmax_attemptZlog_infoattemptZ
start_timeZ&_should_record_body_position_for_retryZ_is_body_retryabler3   ZcheckerZbase_clientZbody_positionresponseZtime_elapsedeZstatus_codeZ
error_coder"   r"   r#   rK     s\   


z6ExponentialBackoffRetryStrategyBase.make_retrying_callc                 C   s   t d)Nz Subclasses should implement this)NotImplementedError)r    r\   rU   r"   r"   r#   r[   P  s   z,ExponentialBackoffRetryStrategyBase.do_sleepc                 C   s
   || _ d S N)rM   )r    rM   r"   r"   r#   add_circuit_breaker_callbackS  s   
z@ExponentialBackoffRetryStrategyBase.add_circuit_breaker_callbackN)rC   rD   rE   rF   r$   rK   r[   ra   r"   r"   r"   r#   rL      s    @rL   c                       s,   e Zd ZdZ	d fdd	Zdd Z  ZS )r;   a4  
        A retry strategy which does exponential backoff with decorrelated jitter. Times used are in seconds and
        the strategy can be described as:

        .. code-block:: none

            min(base_sleep_time_seconds * exponent_growth_factor ** (attempt) + random(0, 1), max_wait_seconds))

        r   c                    s(   t t| j||||fi | || _dS )ah  
        Creates a new instance of an exponential backoff with Decorrelated jitter retry strategy.

        :param int base_sleep_time_seconds:
            The base amount to sleep by, in seconds

        :param int exponent_growth_factor:
            The exponent part of our backoff. We will raise take this value and raising it to the power
            of attempts and then multiply this with base_sleep_time_seconds

        :param int max_wait_between_calls_seconds:
            The maximum time we will wait between calls, in seconds

        :param retry_checkers.RetryCheckerContainer checker_container:
            The checks to run to determine whether a failed call should be retried

        :param int decorrelated_jitter (optional):
            The amount of time in seconds (default 1) to be used as de-correlated jitter between subsequent retries.
        N)superr;   r$   r
   )r    r4   r5   r6   r7   r
   r!   	__class__r"   r#   r$   b  s   
z>ExponentialBackOffWithDecorrelatedJitterRetryStrategy.__init__c                 C   s(   t | j| j| j|| j}t| d S r`   )r   Z;get_exponential_backoff_with_decorrelated_jitter_sleep_timer4   r5   r6   r
   rV   sleepr    r\   rU   Zsleep_time_subsecondsr"   r"   r#   r[   |  s   z>ExponentialBackOffWithDecorrelatedJitterRetryStrategy.do_sleep)r   rC   rD   rE   rF   r$   r[   __classcell__r"   r"   rc   r#   r;   W  s
    r;   c                       (   e Zd ZdZ fddZdd Z  ZS )r=   a  
    A retry strategy which does exponential backoff and full jitter. Times used are in seconds and
    the strategy can be described as:

    .. code-block:: none

        random(0, min(base_sleep_time_seconds * exponent_growth_factor ** (attempt), max_wait_seconds))

    c                    "   t t| j||||fi | dS )a  
        Creates a new instance of an exponential backoff with full jitter retry strategy.

        :param int base_sleep_time_seconds:
            The base amount to sleep by, in seconds

        :param int exponent_growth_factor:
            The exponent part of our backoff. We will raise take this value and raising it to the power
            of attempts and then multiply this with base_sleep_time_seconds

        :param int max_wait_between_calls_seconds:
            The maximum time we will wait between calls, in seconds

        :param retry_checkers.RetryCheckerContainer checker_container:
            The checks to run to determine whether a failed call should be retried
        N)rb   r=   r$   rN   rc   r"   r#   r$     
   

z6ExponentialBackoffWithFullJitterRetryStrategy.__init__c                 C   $   t | j| j| j|}t| d S r`   )r   3get_exponential_backoff_with_full_jitter_sleep_timer4   r5   r6   rV   re   rf   r"   r"   r#   r[     s   z6ExponentialBackoffWithFullJitterRetryStrategy.do_sleeprg   r"   r"   rc   r#   r=     s    
r=   c                       ri   )r?   a  
    A retry strategy which does exponential backoff and equal jitter. Times used are in seconds and
    the strategy can be described as:

    .. code-block:: none

        exponential_backoff_sleep = min(base_sleep_time_seconds * exponent_growth_factor ** (attempt), max_wait_seconds)
        sleep_with_jitter = (exponential_backoff_sleep / 2) + random(0, exponential_backoff_sleep / 2)

    c                    rj   )a  
        Creates a new instance of an exponential backoff with equal jitter retry strategy.

        :param int base_sleep_time_seconds:
            The base amount to sleep by, in seconds

        :param int exponent_growth_factor:
            The exponent part of our backoff. We will raise take this value and raising it to the power
            of attemps and then multiply this with base_sleep_time_seconds

        :param int max_wait_between_calls_seconds:
            The maximum time we will wait between calls, in seconds

        :param retry_checkers.RetryCheckerContainer checker_container:
            The checks to run to determine whether a failed call should be retried
        N)rb   r?   r$   rN   rc   r"   r#   r$     rk   z7ExponentialBackoffWithEqualJitterRetryStrategy.__init__c                 C   rl   r`   )r   4get_exponential_backoff_with_equal_jitter_sleep_timer4   r5   r6   rV   re   r    r\   rU   Zsleep_time_secondsr"   r"   r#   r[     s   z7ExponentialBackoffWithEqualJitterRetryStrategy.do_sleeprg   r"   r"   rc   r#   r?     s    r?   c                       ri   )rA   a$  
    A retry strategy that does exponential backoff and full jitter for most retries, but uses exponential backoff with
    equal jitter for throttles. This provides a reasonable distribution of retry times for most retryable error cases,
    but for throttles guarantees some sleep time
    c                    rj   )a  
        Creates a new instance of the retry strategy.

        :param int base_sleep_time_seconds:
            The base amount to sleep by, in seconds

        :param int exponent_growth_factor:
            The exponent part of our backoff. We will raise take this value and raising it to the power
            of attemps and then multiply this with base_sleep_time_seconds

        :param int max_wait_between_calls_seconds:
            The maximum time we will wait between calls, in seconds

        :param retry_checkers.RetryCheckerContainer checker_container:
            The checks to run to determine whether a failed call should be retried
        N)rb   rA   r$   rN   rc   r"   r#   r$     rk   zGExponentialBackoffWithFullJitterEqualForThrottlesRetryStrategy.__init__c                 C   sh   t |tr"|jdkrt| j| j| j|}nt| j| j| j|}nt| j| j| j|}t	
| d S )Ni  )
isinstancer   rS   r   rn   r4   r5   r6   rm   rV   re   ro   r"   r"   r#   r[     s   

zGExponentialBackoffWithFullJitterEqualForThrottlesRetryStrategy.do_sleeprg   r"   r"   rc   r#   rA     s    rA   )
exceptionsr    r   r   Zoci.utilr   r   r	   rV   r<   r>   r@   r   r   objectr   r8   rL   r;   r=   r?   rA   r"   r"   r"   r#   <module>   s$    Jf+%%