
    !/ir2              
          d Z ddlZddlZddlmZ ddlmZmZmZm	Z	m
Z
 ddlmZmZ ddlmZ ddlmZ ddlZddlmZ  G d	 d
e      Ze G d d             Z G d d      Z G d de      Z G d d      Z e       ZdedefdZdefdZde	fdZedk(  r/ddl Z  e!e jD                        dkD  re jD                  d   Z#e#dk(  r+ejI                         Z% e& ejN                  e%d             ye#dk(  r eddd       Z( e&d!        e)d      D ]  Z*	 e(5  e*d"k  r e+d#      	 ddd         e&d&e(j\                  j^                           e&d'e(ja                                  e&d(        ejb                  d)        e&d*e(j\                  j^                          y e&d+e#         e&d,       y e&d-        e&d,       yy# 1 sw Y   xY w# e+ef$ r+Z, e&d$e*dz    d% e-e,      j>                          Y dZ,[,dZ,[,ww xY w).a>  
Genesis Circuit Breaker
========================
Implements the Circuit Breaker pattern for graceful service degradation.

States:
- CLOSED: Normal operation, requests flow through
- OPEN: Service failed, requests immediately return fallback
- HALF_OPEN: Testing if service recovered

Usage:
    from circuit_breaker import CircuitBreaker, CircuitState

    # Create breaker for Redis
    redis_breaker = CircuitBreaker(
        name="redis",
        failure_threshold=3,
        recovery_timeout=30,
        half_open_requests=2
    )

    # Use as decorator
    @redis_breaker
    def get_from_redis(key):
        return redis_client.get(key)

    # Or use context manager
    with redis_breaker:
        result = redis_client.get(key)

    # Check state
    if redis_breaker.state == CircuitState.OPEN:
        use_fallback()
    N)Enum)CallableAnyOptionalDictList)	dataclassfieldwraps)datetime)Pathc                       e Zd ZdZdZdZdZy)CircuitStatezCircuit breaker states.closedopen	half_openN)__name__
__module____qualname____doc__CLOSEDOPEN	HALF_OPEN     -/mnt/e/genesis-system/core/circuit_breaker.pyr   r   /   s    !FDIr   r   c                       e Zd ZU dZdZeed<   dZeed<   dZeed<   dZ	eed<   dZ
ee   ed<   dZee   ed	<    ee
      Zee   ed<   defdZy)CircuitStatsz!Statistics for a circuit breaker.r   total_callssuccessful_callsfailed_callsrejected_callsNlast_failure_timelast_success_time)default_factorystate_changesreturnc           
          | j                   | j                  | j                  | j                  | j                  t	        d| j                         z  | j
                  | j                  | j                  dd  dS )N   i)r    r!   r"   r#   success_ratelast_failurelast_successr'   )r    r!   r"   r#   maxr$   r%   r'   selfs    r   to_dictzCircuitStats.to_dictA   sm    ++ $ 5 5 --"11 11C4;K;K4LL 22 22!//5	
 		
r   )r   r   r   r   r    int__annotations__r!   r"   r#   r$   r   floatr%   r
   listr'   r   r   r1   r   r   r   r   r   6   sk    +KcL#NC)-x-)-x- %d ;M4:;

 

r   r   c                       e Zd ZdZdddeffdedededed	ef
d
Z	e
defd       Ze
defd       ZdefdZdeddfdZddZddee   ddfdZddZddZdefdZdedefdZd Zd ZdedefdZy)CircuitBreakerap  
    Circuit breaker for protecting against cascading failures.

    Args:
        name: Identifier for this circuit
        failure_threshold: Failures before opening circuit
        recovery_timeout: Seconds before trying half-open
        half_open_requests: Successful requests needed to close
        exceptions: Exception types to catch (default: Exception)
             >@   namefailure_thresholdrecovery_timeouthalf_open_requests
exceptionsc                     || _         || _        || _        || _        || _        t
        j                  | _        d| _        d| _	        d | _
        t        j                         | _        t               | _        y )Nr   )r;   r<   r=   r>   r?   r   r   _state_failure_count_success_count_last_failure_time	threadingRLock_lockr   _stats)r0   r;   r<   r=   r>   r?   s         r   __init__zCircuitBreaker.__init__Z   sf     	!2 0"4$"))37__&
"nr   r(   c                     | j                   5  | j                  t        j                  k(  r/| j	                         r| j                  t        j                         | j                  cddd       S # 1 sw Y   yxY w)z3Get current state, checking for automatic recovery.N)rG   rA   r   r   _should_attempt_recovery_transition_tor   r/   s    r   statezCircuitBreaker.stateo   sY     ZZ 	{{l///002''(>(>?;;		 	 	s   AA//A8c                 <    | j                   t        j                  k7  S )z!Check if circuit allows requests.)rM   r   r   r/   s    r   is_availablezCircuitBreaker.is_availablex   s     zz\....r   c                 x    | j                   yt        j                         | j                   z
  | j                  k\  S )z,Check if enough time passed to try recovery.T)rD   timer=   r/   s    r   rK   z'CircuitBreaker._should_attempt_recovery}   s3    ""*yy{T4448M8MMMr   	new_stateNc                    | j                   }|| _         |t        j                  k(  rd| _        d| _        n|t        j
                  k(  rd| _        | j                  j                  j                  |j                  |j                  t        j                         j                         d       t        d| j                   d|j                   d|j                          y)zTransition to a new state.r   )fromto	timestampz[CircuitBreaker:z] z -> N)rA   r   r   rB   rC   r   rH   r'   appendvaluer   now	isoformatprintr;   )r0   rR   	old_states      r   rL   zCircuitBreaker._transition_to   s    KK	+++"#D"#D,000"#D!!((OO//!113*
 	 	 2ioo->d9??BSTUr   c                    | j                   5  | j                  xj                  dz  c_        | j                  xj                  dz  c_        t	        j                         | j                  _        | j                  t        j                  k(  rM| xj                  dz  c_	        | j                  | j                  k\  r| j                  t        j                         ddd       y# 1 sw Y   yxY w)zRecord a successful call.r*   N)rG   rH   r    r!   rQ   r%   rA   r   r   rC   r>   rL   r   r/   s    r   record_successzCircuitBreaker.record_success   s    ZZ 	=KK##q(#KK((A-(,0IIKDKK){{l444##q(#&&$*A*AA''(;(;<	= 	= 	=s   CC""C+excc                    | j                   5  | j                  xj                  dz  c_        | j                  xj                  dz  c_        t	        j                         | j                  _        t	        j                         | _        | xj                  dz  c_        | j                  t        j                  k(  r | j                  t        j                         nU| j                  t        j                  k(  r8| j                  | j                  k\  r| j                  t        j                         ddd       y# 1 sw Y   yxY w)zRecord a failed call.r*   N)rG   rH   r    r"   rQ   r$   rD   rB   rA   r   r   rL   r   r   r<   )r0   r_   s     r   record_failurezCircuitBreaker.record_failure   s    ZZ 	;KK##q(#KK$$)$,0IIKDKK)&*iikD#1${{l444##L$5$56 3 33&&$*@*@@''(9(9:	; 	; 	;s   D"D88Ec                     | j                   5  | j                  xj                  dz  c_        | j                  xj                  dz  c_        ddd       y# 1 sw Y   yxY w)z&Record a rejected call (circuit open).r*   N)rG   rH   r    r#   r/   s    r   record_rejectionzCircuitBreaker.record_rejection   sH    ZZ 	,KK##q(#KK&&!+&	, 	, 	,s   ?AAc                     | j                   5  | j                  t        j                         d| _        d| _        d| _        ddd       y# 1 sw Y   yxY w)z+Manually reset the circuit to closed state.r   N)rG   rL   r   r   rB   rC   rD   r/   s    r   resetzCircuitBreaker.reset   sJ    ZZ 	+ 3 34"#D"#D&*D#		+ 	+ 	+s   5AAc                     | j                   5  | j                  j                         }| j                  |d<   | j                  j
                  |d<   | j                  |d<   |cddd       S # 1 sw Y   yxY w)zGet current statistics.r;   rM   failure_countN)rG   rH   r1   r;   rA   rX   rB   )r0   statss     r   	get_statszCircuitBreaker.get_stats   sc    ZZ 	KK'')E IIE&M![[..E'N%)%8%8E/"	 	 	s   AA**A3funcc                 2     t               fd       }|S )zUse as decorator.c                  0     j                   g| i |S N)call)argskwargsrj   r0   s     r   wrapperz(CircuitBreaker.__call__.<locals>.wrapper   s    499T3D3F33r   r   )r0   rj   rq   s   `` r   __call__zCircuitBreaker.__call__   s    	t	4 
	4r   c                 p    | j                   s)| j                          t        d| j                   d      | S )zContext manager entry.	Circuit '	' is OPEN)rO   rc   CircuitOpenErrorr;   r/   s    r   	__enter__zCircuitBreaker.__enter__   s4      !!#"Ytyyk#CDDr   c                 |    || j                          y|r't        || j                        r| j                  |       y)zContext manager exit.F)r^   
issubclassr?   ra   )r0   exc_typeexc_valexc_tbs       r   __exit__zCircuitBreaker.__exit__   s<    !  *Xt?(r   c                     | j                   s)| j                          t        d| j                   d      	  ||i |}| j	                          |S # | j
                  $ r}| j                  |        d}~ww xY w)z1Execute function with circuit breaker protection.rt   ru   N)rO   rc   rv   r;   r^   r?   ra   )r0   rj   ro   rp   resultes         r   rn   zCircuitBreaker.call   sy      !!#"Ytyyk#CDD	4*6*F!M 	"	s   A A7 A22A7r(   Nrm   )r   r   r   r   	Exceptionstrr2   r4   tuplerI   propertyr   rM   boolrO   rK   rL   r^   r   ra   rc   re   r   ri   r   rr   rw   r}   r   rn   r   r   r   r7   r7   N   s	   	 "#"&"#&L%% %  	%
  % %* |   /d / /N$ NV V V&
=;(9"5 ; ; ,+4 X (  s r   r7   c                       e Zd ZdZy)rv   z1Raised when circuit is open and call is rejected.N)r   r   r   r   r   r   r   rv   rv      s    ;r   rv   c                       e Zd ZdZddee   fdZdddeffded	ed
e	dede
defdZdedee   fdZdedefdZdeeef   fdZdefdZddZddZy)CircuitBreakerRegistryag  
    Registry for managing multiple circuit breakers.

    Usage:
        registry = CircuitBreakerRegistry()
        registry.register("redis", failure_threshold=3)
        registry.register("qdrant", failure_threshold=5)

        # Get a breaker
        redis_cb = registry.get("redis")

        # Get all stats
        stats = registry.get_all_stats()
    Npersist_pathc                 x    i | _         t        j                         | _        |rt	        |      | _        y d | _        y rm   )	_breakersrE   LockrG   r   _persist_path)r0   r   s     r   rI   zCircuitBreakerRegistry.__init__  s-    46^^%
3?T,/Tr   r8   r9   r:   r;   r<   r=   r>   r?   r(   c                     | j                   5  || j                  v r| j                  |   cddd       S t        |||||      }|| j                  |<   |cddd       S # 1 sw Y   yxY w)zRegister a new circuit breaker.N)r;   r<   r=   r>   r?   )rG   r   r7   )r0   r;   r<   r=   r>   r?   breakers          r   registerzCircuitBreakerRegistry.register  sp     ZZ 	t~~%~~d+	 	 %"3!1#5%G $+DNN4 	 	 	s   A AA'c                 8    | j                   j                  |      S )zGet a circuit breaker by name.)r   get)r0   r;   s     r   r   zCircuitBreakerRegistry.get  s    ~~!!$''r   c                 b    || j                   vr | j                  |fi |S | j                   |   S )z+Get existing or create new circuit breaker.)r   r   )r0   r;   rp   s      r   get_or_createz$CircuitBreakerRegistry.get_or_create#  s5     t~~% 4==000~~d##r   c                     | j                   j                         D ci c]  \  }}||j                          c}}S c c}}w )z$Get stats from all circuit breakers.)r   itemsri   )r0   r;   cbs      r   get_all_statsz$CircuitBreakerRegistry.get_all_stats-  s2    59^^5I5I5KLrblln$LLLs   =c           	         | j                         }|j                         D cg c]  \  }}|d   dk(  s| }}}|j                         D cg c]  \  }}|d   dk(  s| }}}t        |      t        |      t        |      t        |      t        |      z
  t        |      z
  ||t        |      dk(  dS c c}}w c c}}w )z#Get health summary of all circuits.rM   r   r   r   )total_circuitsr   r   r   open_circuitshalf_open_circuitshealthy)r   r   len)r0   rh   nsr   r   s         r   get_health_summaryz)CircuitBreakerRegistry.get_health_summary1  s    ""$',{{}Mtq!'
f8LMM#(;;=N41aAgJ+4MQN	N "%j&Y%j3}#55IF*"+=)Q.
 	
 NNs   B9B9B? B?c                 b    | j                   j                         D ]  }|j                           y)zReset all circuit breakers.N)r   valuesre   )r0   r   s     r   	reset_allz CircuitBreakerRegistry.reset_allA  s'    ..'') 	BHHJ	r   c                 \   | j                   sy	 | j                         }| j                   j                  j                  dd       t	        | j                   d      5 }t        j                  ||d       ddd       y# 1 sw Y   yxY w# t        $ r}t        d|        Y d}~yd}~ww xY w)z&Persist circuit breaker stats to file.NT)parentsexist_okwr:   indentz-[!] Failed to persist circuit breaker stats: )	r   r   parentmkdirr   jsondumpr   r[   )r0   rh   fr   s       r   persistzCircuitBreakerRegistry.persistF  s    !!	G&&(E%%++D4+Hd((#. .!		%1-. . . 	GA!EFF	Gs6   AB
 A>5B
 >BB
 B
 
	B+B&&B+rm   r   )r   r   r   r   r   r   rI   r   r2   r4   r   r7   r   r   r   r   r   r   r   r   r   r   r   r   r      s    JXc] J "#"&"#&L   	
    
.( ( 8 ($$ 
	$MtCI M
D 
 
Gr   r   r;   r(   c                 .    t        j                  | fi |S )z5Get or create a circuit breaker from global registry.)_global_registryr   )r;   rp   s     r   get_circuit_breakerr   X  s    ))$9&99r   c                      t         S )z(Get the global circuit breaker registry.)r   r   r   r   get_registryr   ]  s    r   c                  *    t         j                         S )z*Get health status of all circuit breakers.)r   r   r   r   r   get_all_statusr   b  s    ..00r   __main__r*   statusr:   r   demo   r8   )r<   r=   zSimulating failures...   zSimulated failurez  Call z: z
Circuit state: zStats: z%
Waiting for recovery timeout (5s)...   zCircuit state after timeout: zUnknown command: z.Usage: python circuit_breaker.py [status|demo]zGenesis Circuit Breaker)2r   rQ   rE   enumr   typingr   r   r   r   r   dataclassesr	   r
   	functoolsr   r   r   pathlibr   r   r   r7   r   rv   r   r   r   r   r   r   r   sysr   argvcmdr   healthr[   dumpsr   rangeiConnectionErrorr   typerM   rX   ri   sleepr   r   r   <module>r      s?  !F    6 6 (    4  
 
 
.] ]@	y 	
^G ^GD *+ :c : :
, 
1 1 z
388}qhhqk(?%88:F*$**VA./F]!aPB*+1X ?? Gq5"12E"FF !G? %bhhnn%567GBLLN+,-:;DJJqM1"((..1ABC %cU+,BC'(>?I "G G ()9: ?GAaC547+;+;*<=>>?s0   GG%GG	GH!H  H