o
    _�¿j%  ã                   @  s°   d Z ddlmZ ddlZddlZddlZddlmZ ddlm	Z	 ddl
mZ ddlmZmZmZmZmZ e d¡Zed	ƒZe	d
d�G dd„ dƒƒZdddœddd„ZddgZdS )uZ  HTTP layer â€” retry policy with exponential backoff and jitter.

Key design decisions vs. original code:
- ``_MAX_RETRIES = 1000`` â†’ configurable, default 5, max 10.
- ``2**attempt`` unbounded sleep â†’ ``min(base**attempt + jitter, cap)`` capped at 30s.
- Session is NOT recreated on every retry â€” only recreated on explicit session error.
é    )ÚannotationsN)ÚCallable)Ú	dataclass)ÚTypeVar)ÚDEFAULT_BACKOFF_BASEÚDEFAULT_BACKOFF_CAP_SÚDEFAULT_BACKOFF_JITTERÚDEFAULT_MAX_RETRIESÚRATE_LIMIT_STATUS_CODESzindiaopt.retryÚTT)Úfrozenc                   @  sz   e Zd ZU dZeZded< eZded< e	Z
ded< eZded< eZded	< ddd„Zddd„Zddd„Zeddd„ƒZdS )ÚRetryPolicyaØ  Immutable retry policy configuration.

    Attributes:
        max_retries:    Maximum number of attempts (including the first).
        backoff_base:   Base for exponential backoff formula.
        backoff_cap:    Maximum sleep duration in seconds.
        jitter:         Maximum random jitter added to each sleep.
        retry_statuses: HTTP status codes that trigger a retry.

    Backoff formula::

        sleep = min(base ** attempt + uniform(0, jitter), cap)
    ÚintÚmax_retriesÚfloatÚbackoff_baseÚbackoff_capÚjitterzfrozenset[int]Úretry_statusesÚattemptÚreturnc                 C  s@   t | j| t d| j¡ | jƒ}t d||d ¡ t 	|¡ |S )z�Compute and sleep for the backoff duration on *attempt* (0-indexed).

        Returns:
            Actual sleep duration in seconds.
        ç        z!Backoff sleep %.2fs (attempt %d).é   )
Úminr   ÚrandomÚuniformr   r   ÚloggerÚdebugÚtimeÚsleep)Úselfr   Úduration© r"   úN/home/dinkstrade/pdmp/venv/lib/python3.10/site-packages/indiaopt/http/retry.pyÚ	sleep_for5   s   þ
zRetryPolicy.sleep_forc                 C  s    t | j| t d| j¡ | jƒS )zmReturn the backoff duration for *attempt* without sleeping.

        Useful for logging and testing.
        r   )r   r   r   r   r   r   )r    r   r"   r"   r#   Úcompute_sleepC   s   þzRetryPolicy.compute_sleepÚstatus_codeÚboolc                 C  s
   || j v S )z2Return ``True`` if *status_code* warrants a retry.)r   )r    r&   r"   r"   r#   Úshould_retry_statusM   s   
zRetryPolicy.should_retry_statusÚsettingsÚobjectc                 C  s0   | t |dtƒt |dtƒt |dtƒt |dtƒd�S )z[Construct a :class:`RetryPolicy` from a :class:`~indiaopt.config.settings.Settings` object.r   r   Úbackoff_cap_secondsÚbackoff_jitter)r   r   r   r   )Úgetattrr	   r   r   r   )Úclsr)   r"   r"   r#   Úfrom_settingsQ   s   



üzRetryPolicy.from_settingsN)r   r   r   r   )r&   r   r   r'   )r)   r*   r   r   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__r	   r   Ú__annotations__r   r   r   r   r   r   r
   r   r$   r%   r(   Úclassmethodr/   r"   r"   r"   r#   r      s   
 



r   Ú	operation)ÚlabelÚon_retryÚfnúCallable[[], T]Úpolicyr7   Ústrr8   ú'Callable[[int, Exception], None] | Noner   c                C  s¦   d}t |jƒD ]=}z| ƒ W   S  tyD } z)|}|dur"|||ƒ t d|d |j||¡ ||jd k r:| |¡ W Y d}~qd}~ww |pRtd|j› d|› d�ƒ‚)aˆ  Execute *fn* with retry logic defined by *policy*.

    Args:
        fn:       Zero-argument callable to execute.
        policy:   :class:`RetryPolicy` governing retry behaviour.
        label:    Human-readable name for logging.
        on_retry: Optional callback invoked with ``(attempt, exc)`` before sleep.

    Returns:
        The return value of *fn* on success.

    Raises:
        The last exception raised by *fn* after all attempts are exhausted.

    Example::

        result = with_retry(
            lambda: session.get(url, timeout=15),
            RetryPolicy(max_retries=5),
            label=f"fetch {symbol}",
        )
    Nz!Attempt %d/%d for '%s' failed: %sr   zAll z attempts for 'z	' failed.)Úranger   Ú	Exceptionr   Úwarningr$   ÚRuntimeError)r9   r;   r7   r8   Úlast_excr   Úexcr"   r"   r#   Ú
with_retry\   s(   
û
€ôrD   )
r9   r:   r;   r   r7   r<   r8   r=   r   r   )r3   Ú
__future__r   Úloggingr   r   Úcollections.abcr   Údataclassesr   Útypingr   Úindiaopt.constantsr   r   r   r	   r
   Ú	getLoggerr   r   r   rD   Ú__all__r"   r"   r"   r#   Ú<module>   s"    
@û3