
    mBNjYT                        d dl Z d dlZd dlmZmZmZmZmZmZm	Z	 d dl
mZ d dlmZmZmZmZ d dlmZmZmZ d dlmZ d dlmZmZ d dlmZ d d	lmZ d d
lmZ d dl m!Z!m"Z" d dl#m$Z$ d dl#m%Z& d dl'm(Z(m)Z)m*Z* d dl+m,Z, d dl-m.Z.m/Z/m0Z0m1Z1m2Z2 d dl3m4Z4  ejj                  e6      Z7e4 G d de"e!             Z8de$fdZ9 G d de"e!      Z: G d d      Z;y)    N)Any	AwaitableCallableListLiteralOptionalUnion)DefaultCommandExecutor)DEFAULT_GRACE_PERIODDatabaseConfigInitialHealthCheckMultiDbConfig)AsyncDatabaseDatabase	Databases)AsyncFailureDetector)HealthCheckHealthCheckPolicy)Retry)BackgroundScheduler)	NoBackoff)AsyncCoreCommandsAsyncRedisModuleCommands)CircuitBreaker)State)InitialHealthCheckFailedErrorNoValidDatabaseExceptionUnhealthyDatabaseException)GeoFailoverReason)ChannelT
EncodableTKeyTPubSubHandlerSubscription)experimentalc                   J   e Zd ZdZdefdZd,dZd Zd Zd Z	de
fd	Zd
eddfdZ	 d-dedefdZdedefdZd
efdZd
edefdZdefdZdefdZd Zd Zdddddedgeeee   f   f   ded e e!   d!ed"e e   f
d#Z"d$ Z#de$e%ef   fd%Z&d& Z'd
edefd'Z(d(e)d)e*d*e*fd+Z+y).MultiDBClientz
    Client that operates on multiple logical Redis databases.
    Should be used in Client-side geographic failover database setups.
    configc           
         |j                         | _        |j                  s|j                         n|j                  | _        |j
                  | _        |j                  j                         | _	        |j                  s|j                         n|j                  | _        |j                  |j                         n|j                  | _        | j                  j!                  | j                         |j"                  | _        |j&                  | _        |j*                  | _        | j,                  j/                  t0        g       t3        | j                  | j                  | j,                  | j                  |j4                  |j6                  | j(                  | j$                        | _        d| _        t=        j>                         | _         tC               | _"        || _#        d | _$        g | _%        d | _&        y )N)failure_detectors	databasescommand_retryfailover_strategyfailover_attemptsfailover_delayevent_dispatcherauto_fallback_intervalF)'r+   
_databaseshealth_checksdefault_health_checks_health_checkshealth_check_interval_health_check_intervalhealth_check_policyvalue_health_check_policyr*   default_failure_detectors_failure_detectorsr-   default_failover_strategy_failover_strategyset_databasesr1   _auto_fallback_intervalr0   _event_dispatcherr,   _command_retryupdate_supported_errorsConnectionRefusedErrorr
   r.   r/   command_executorinitializedasyncioLock_hc_lockr   _bg_scheduler_config_recurring_hc_task	_hc_tasks_half_open_state_task)selfr(   s     m/Users/ahmed/devFolder/Ultron/claude-voice/.venv/lib/python3.12/site-packages/redis/asyncio/multidb/client.py__init__zMultiDBClient.__init__(   s    **, '' ((*%% 	
 '-&B&B#&&,,. 	!
 ++ ,,.)) 	 ''/ ,,.)) 	
 	--doo>'-'D'D$!'!8!8$22335K4LM 6"55oo--"55$66!00!33#'#?#?	!
 !02"&%)"    returnc                 Z   K   | j                   s| j                          d {    | S 7 wN)rF   
initializerO   s    rP   
__aenter__zMultiDBClient.__aenter__U   s)     //### $s    +)+c                   K   | j                   r| j                   j                          | j                  r| j                  j                          | j                  D ]  }|j                           | j                  j                          d {    | j                  j                  r7| j                  j                  j                  j                          d {    y y 7 R7 wrU   )
rL   cancelrN   rM   r:   closerE   active_databaseclientaclose)rO   hc_tasks     rP   r^   zMultiDBClient.acloseZ   s     ""##**,%%&&--/~~GNN & ''--///   00''77>>EEGGG 1 	0 Hs%   BC$C AC$C"C$"C$c                 @   K   | j                          d {    y 7 wrU   r^   rO   exc_type	exc_value	tracebacks       rP   	__aexit__zMultiDBClient.__aexit__j        kkm   c                   K   | j                          d{    t        j                  | j                  j	                  | j
                  | j                              | _        d}| j                  D ]h  \  }}|j                  j                  | j                         |j                  j                  t        j                  k(  sS|rV|| j                  _        d}j |st#        d      d| _        y7 ڭw)zT
        Perform initialization of databases to define their initial state.
        NFTz4Initial connection failed - no active database found)_perform_initial_health_checkrG   create_taskrJ   run_recurring_asyncr7   _check_databases_healthrL   r2   circuiton_state_changed!_on_circuit_state_change_callbackstateCBStateCLOSEDrE   _active_databaser   rF   )rO   is_active_db_founddatabaseweights       rP   rV   zMultiDBClient.initializem   s      00222 #*"5"522++,,#
 # $Hf--d.T.TU %%7@R :B%%6%)" !0 "*F   9 	3s   C3C1B,C3C3+C3c                     | j                   S )zE
        Returns a sorted (by weight) list of all databases.
        )r2   rW   s    rP   get_databaseszMultiDBClient.get_databases   s     rR   rv   Nc                   K   d}| j                   D ]  \  }}||k(  sd} n |st        d      | j                  |       d{    |j                  j                  t
        j                  k(  rT| j                   j                  d      d   \  }}| j                  j                  |t        j                         d{    yt        d      7 7 w)zL
        Promote one of the existing databases to become an active.
        NT/Given database is not a member of database list   r   z1Cannot set active database, database is unhealthy)r2   
ValueError_check_db_healthrn   rq   rr   rs   	get_top_nrE   set_active_databaser   MANUALr   )rO   rv   existsexisting_db_highest_weighted_dbs         rP   r   z!MultiDBClient.set_active_database   s      "ooNKh& .
 NOO##H---!!W^^3%)__%>%>q%A!%D"'';;+22   &?
 	
 	.s)   C&CCA9C=C>CCskip_initial_health_checkc                   K   |j                   j                  dt        dt                     i       |j                  r< | j
                  j                  j                  |j                  fi |j                   }n|j                  r_|j                  j                  t        dt                            | j
                  j                  j                  |j                        }n& | j
                  j                  di |j                   }|j                  |j                         n|j                  }t        |||j                  |j                        }	 | j                  |       d{    | j                   j#                  d      d   \  }}| j                   j%                  ||j                         | j'                  ||       d{    y7 f# t        $ r |s Y rw xY w7 w)	z
        Adds a new database to the database list.

        Args:
            config: DatabaseConfig object that contains the database configuration.
            skip_initial_health_check: If True, adds the database even if it is unhealthy.
        retryr   )retriesbackoff)connection_poolN)r]   rn   rw   health_check_urlr|    )client_kwargsupdater   r   from_urlrK   client_class	from_pool	set_retryrn   default_circuit_breakerr   rw   r   r~   r   r2   r   add_change_active_database)rO   r(   r   r]   rn   rv   r   highest_weights           rP   add_databasezMultiDBClient.add_database   s     	##WeAy{.S$TU??7T\\..77#)#7#7F &&uQ	'LM\\..88 & 0 0 9 F /T\\..F1E1EFF ~~% **, 	 ==#44	
	''111
 /3oo.G.G.J1.M+^Hhoo6**85HIII 2) 	, -	 	JsI   EG)G ,G-G 1AG)G'G)G G$!G)#G$$G)new_databasehighest_weight_databasec                    K   |j                   |j                   kD  r[|j                  j                  t        j                  k(  r3| j
                  j                  |t        j                         d {    y y y 7 wrU   )	rw   rn   rq   rr   rs   rE   r   r   	AUTOMATIC)rO   r   r   s      rP   r   z%MultiDBClient._change_active_database   so      "9"@"@@$$**gnn<'';;/99   = As   A.A:0A81A:c                 H  K   | j                   j                  |      }| j                   j                  d      d   \  }}||k  r[|j                  j                  t
        j                  k(  r3| j                  j                  |t        j                         d{    yyy7 w)z<
        Removes a database from the database list.
        r|   r   N)r2   remover   rn   rq   rr   rs   rE   r   r   r   )rO   rv   rw   r   r   s        rP   remove_databasezMultiDBClient.remove_database   s      ''1.2oo.G.G.J1.M+^ f$#++11W^^C'';;#%6%=%=   D %s   BB"B B"rw   c                 $  K   d}| j                   D ]  \  }}||k(  sd} n |st        d      | j                   j                  d      d   \  }}| j                   j                  ||       ||_        | j                  ||       d{    y7 w)z<
        Updates a database from the database list.
        NTr{   r|   r   )r2   r}   r   update_weightrw   r   )rO   rv   rw   r   r   r   r   r   s           rP   update_database_weightz$MultiDBClient.update_database_weight   s      "ooNKh& .
 NOO.2oo.G.G.J1.M+^%%h7 **85HIIIs   BA+BB	Bfailure_detectorc                 :    | j                   j                  |       y)z>
        Adds a new failure detector to the database.
        N)r<   append)rO   r   s     rP   add_failure_detectorz"MultiDBClient.add_failure_detector  s     	&&'78rR   healthcheckc                    K   | j                   4 d{    | j                  j                  |       ddd      d{    y7 07 # 1 d{  7  sw Y   yxY ww)z:
        Adds a new health check to the database.
        N)rI   r5   r   )rO   r   s     rP   add_health_checkzMultiDBClient.add_health_check  s8      ===&&{3 !======sA   AAAAAAAAAAAAc                    K   | j                   s| j                          d{     | j                  j                  |i | d{   S 7 (7 w)zB
        Executes a single command and return its result.
        N)rF   rV   rE   execute_commandrO   argsoptionss      rP   r   zMultiDBClient.execute_command  sK      //###:T**::DLGLLL $Ls!    AA#AAAAc                     t        |       S )z:
        Enters into pipeline mode of the client.
        )PipelinerW   s    rP   pipelinezMultiDBClient.pipeline&  s     ~rR   F
shard_hintvalue_from_callablewatch_delayfuncr   watchesr   r   r   c                   K   | j                   s| j                          d{     | j                  j                  |g||||d d{   S 7 .7 w)z3
        Executes callable as transaction.
        Nr   )rF   rV   rE   execute_transaction)rO   r   r   r   r   r   s         rP   transactionzMultiDBClient.transaction,  sg      //###>T**>>

 " 3#
 
 	
 $
s!    AA)AAAAc                 n   K   | j                   s| j                          d{    t        | fi |S 7 w)z
        Return a Publish/Subscribe object. With this object, you can
        subscribe to channels and listen for messages that get published to
        them.
        N)rF   rV   PubSub)rO   kwargss     rP   pubsubzMultiDBClient.pubsubB  s6      //###d%f%% $s    535c                 z  K   i }g | _         | j                  D ]I  \  }}t        j                  | j	                  |            }|||<   | j                   j                  |       K t        j                  | j                   ddi d{   }t        | j                   |      D ci c]  \  }}||   | }}}|j                         D ]g  \  }}t        |t              s|j                  }t        j                  |j                  _        t         j#                  d|j$                         d||<   i |S 7 c c}}w w)zk
        Runs health checks as a recurring task.
        Runs health checks against all databases.
        return_exceptionsTNz%Health check failed, due to exception)exc_infoF)rM   r2   rG   rk   r~   r   gatherzipitems
isinstancer   rv   rr   OPENrn   rq   loggerdebugoriginal_exception)	rO   
task_to_dbrv   r   taskresultsresult
db_resultsunhealthy_dbs	            rP   rm   z%MultiDBClient._check_databases_healthM  s-    
 46
??KHa&&t'<'<X'FGD'JtNN!!$' +
  O$OO :=T^^W9U
9UvJtf$9U 	 
 !+ 0 0 2Hf&"<=%-4\\$$*;#66  
 ,1
<( !3 ' P
s+   BD;D3D;$D54)D;AD;5D;c                   K   | j                          d{   }d}| j                  j                  t        j                  k(  rd|j                         v}n| j                  j                  t        j                  k(  r)t        |j                               t        |      dz  kD  }n9| j                  j                  t        j                  k(  rd|j                         v }|s"t        d| j                  j                         y7 w)zj
        Runs initial health check and evaluate healthiness based on initial_health_check_policy.
        NTF   z:Initial health check failed. Initial health check policy: )rm   rK   initial_health_check_policyr   ALL_AVAILABLEvaluesMAJORITY_AVAILABLEsumlenONE_AVAILABLEr   )rO   r   
is_healthys      rP   rj   z+MultiDBClient._perform_initial_health_checko  s      4466
<<337I7W7WWgnn&66JLL44!445 W^^-.W1AAJLL448J8X8XX!11J/LT\\MuMuLvw   7s   DDC/Dc                   K   | j                   j                  | j                  |       d{   }|sH|j                  j                  t
        j                  k7  rt
        j                  |j                  _        |S |rF|j                  j                  t
        j                  k7  rt
        j                  |j                  _        |S 7 w)zO
        Runs health checks on the given database until first failure.
        N)r:   executer5   rn   rq   rr   r   rs   )rO   rv   r   s      rP   r~   zMultiDBClient._check_db_health  s     
  44<<
 

 %%5)0  &H,,22gnnD%,^^H"
s   *CCBCrn   	old_state	new_statec                    t        j                         }|t        j                  k(  r4t        j                  | j                  |j                              | _        y |t        j                  k(  rQ|t        j                  k(  r>t        j                  d|j                   d       |j                  t        t        |       |t        j                  k7  r8|t        j                  k(  r$t        j                  d|j                   d       y y y )Nz	Database z- is unreachable. Failover has been initiated.z is reachable again.)rG   get_running_looprr   	HALF_OPENrk   r~   rv   rN   rs   r   r   warning
call_laterr   _half_open_circuitinfo)rO   rn   r   r   loops        rP   rp   z/MultiDBClient._on_circuit_state_change_callback  s     '')))))0)<)<%%g&6&67*D& &9+DNNG,,--Z[ OO02DgN&9+FKK)G$4$4#55IJK ,G&rR   )rO   r'   rS   r'   )T),__name__
__module____qualname____doc__r   rQ   rX   r^   rf   rV   r   ry   r   r   r   boolr   r   r   floatr   r   r   r   r   r   r   r   r	   r   r   r"   r   strr   r   dictr   rm   rj   r~   r   rr   rp   r   rR   rP   r'   r'   !   sz   
+*} +*Z
H " Hy 
- 
D 
8 IM/J$/JAE/Jb	)	DQ	m J] JE J&95I 94+ 4M %)$)'+

|U3	#+>%??@
 
 SM	

 "
 e_
,	& tHdN/C  D0}  $L%L29LFMLrR   r'   rn   c                 .    t         j                  | _        y rU   )rr   r   rq   )rn   s    rP   r   r     s    %%GMrR   c                       e Zd ZU dZdZed   ed<   defdZddZ	d Z
d	 Zd
 ZdefdZdefdZddZddZddZd Zdee   fdZy)r   zG
    Pipeline implementation for multiple logical Redis databases.
    T_is_async_clientr]   c                      g | _         || _        y rU   )_command_stack_client)rO   r]   s     rP   rQ   zPipeline.__init__  s     rR   rS   c                    K   | S wrU   r   rW   s    rP   rX   zPipeline.__aenter__          c                    K   | j                          d {    | j                  j                  |||       d {    y 7 *7 wrU   )resetr   rf   rb   s       rP   rf   zPipeline.__aexit__  s:     jjlll$$Xy)DDD 	Ds   AA$AAAAc                 >    | j                         j                         S rU   )_async_self	__await__rW   s    rP   r   zPipeline.__await__  s    !++--rR   c                    K   | S wrU   r   rW   s    rP   r   zPipeline._async_self  r   r   c                 ,    t        | j                        S rU   )r   r   rW   s    rP   __len__zPipeline.__len__  s    4&&''rR   c                      y)z1Pipeline instances should always evaluate to TrueTr   rW   s    rP   __bool__zPipeline.__bool__  s    rR   Nc                    K   g | _         y wrU   )r   rW   s    rP   r   zPipeline.reset  s      s   	c                 @   K   | j                          d{    y7 w)zClose the pipelineN)r   rW   s    rP   r^   zPipeline.aclose  s     jjlrh   c                 @    | j                   j                  ||f       | S )ar  
        Stage a command to be executed when execute() is next called

        Returns the current Pipeline object back so commands can be
        chained together, such as:

        pipe = pipe.set('foo', 'bar').incr('baz').decr('bang')

        At some other point, you can then run: pipe.execute(),
        which will execute all commands queued in the pipe.
        )r   r   r   s      rP   pipeline_execute_commandz!Pipeline.pipeline_execute_command  s!     	""D'?3rR   c                 &     | j                   |i |S )zAdds a command to the stack)r  rO   r   r   s      rP   r   zPipeline.execute_command  s    ,t,,d=f==rR   c                 t  K   | j                   j                  s"| j                   j                          d{    	 | j                   j                  j	                  t        | j                               d{   | j                          d{    S 7 ]7 7 	# | j                          d{  7   w xY ww)z0Execute all the commands in the current pipelineN)r   rF   rV   rE   execute_pipelinetupler   r   rW   s    rP   r   zPipeline.execute  s     ||'',,))+++	66GGd))*  **, , $**,sV   4B8BB8;B 7B8B ;B8BB8B B8B5.B1/B55B8)rO   r   rS   r   rS   N)rS   r   )r   r   r   r   r   r   __annotations__r'   rQ   rX   rf   r   r   intr   r   r   r   r^   r  r   r   r   r   r   rR   rP   r   r     su     '+gdm*} E.( ($ !>
tCy 
rR   r   c                       e Zd ZdZdefdZddZddZd Ze	de
fd	       Zd
efdZd
eez  deddfdZd
efdZd
eez  deddfdZd Z	 dde
dee   fdZddddeddfdZy)r   z2
    PubSub object for multi database client.
    r]   c                 ^    || _          | j                   j                  j                  di | y)zInitialize the PubSub object for a multi-database client.

        Args:
            client: MultiDBClient instance to use for pub/sub operations
            **kwargs: Additional keyword arguments to pass to the underlying pubsub implementation
        Nr   )r   rE   r   )rO   r]   r   s      rP   rQ   zPubSub.__init__  s(     ,%%,,6v6rR   rS   c                    K   | S wrU   r   rW   s    rP   rX   zPubSub.__aenter__  r   r   Nc                 @   K   | j                          d {    y 7 wrU   ra   rb   s       rP   rf   zPubSub.__aexit__  rg   rh   c                 h   K   | j                   j                  j                  d       d {   S 7 w)Nr^   r   rE   execute_pubsub_methodrW   s    rP   r^   zPubSub.aclose  s'     \\22HHRRRRs   )202c                 V    | j                   j                  j                  j                  S rU   )r   rE   active_pubsub
subscribedrW   s    rP   r  zPubSub.subscribed  s    ||,,::EEErR   r   c                 l   K    | j                   j                  j                  dg|  d {   S 7 w)Nr   r  rO   r   s     rP   r   zPubSub.execute_command  s:     HT\\22HH
 $
 
 	
 
   +424r   c                 r   K    | j                   j                  j                  dg|i | d{   S 7 w)aE  
        Subscribe to channel patterns. Patterns supplied as keyword arguments
        expect a pattern name as the key and a callable as the value. A
        pattern's callable will be invoked automatically when a message is
        received on that pattern rather than producing a message via
        ``listen()``.
        
psubscribeNr  r  s      rP   r  zPubSub.psubscribe  sE      IT\\22HH

#)
 
 	
 
   .757c                 l   K    | j                   j                  j                  dg|  d{   S 7 w)zj
        Unsubscribe from the supplied patterns. If empty, unsubscribe from
        all patterns.
        punsubscribeNr  r  s     rP   r  zPubSub.punsubscribe(  s=     
 IT\\22HH
!
 
 	
 
r  c                 r   K    | j                   j                  j                  dg|i | d{   S 7 w)aR  
        Subscribe to channels. Channels supplied as keyword arguments expect
        a channel name as the key and a callable as the value. A channel's
        callable will be invoked automatically when a message is received on
        that channel rather than producing a message via ``listen()`` or
        ``get_message()``.
        	subscribeNr  r  s      rP   r   zPubSub.subscribe1  sE      IT\\22HH

"(
 
 	
 
r  c                 l   K    | j                   j                  j                  dg|  d{   S 7 w)zi
        Unsubscribe from the supplied channels. If empty, unsubscribe from
        all channels
        unsubscribeNr  r  s     rP   r"  zPubSub.unsubscribe?  s=     
 IT\\22HH
 
 
 	
 
r  ignore_subscribe_messagestimeoutc                 n   K   | j                   j                  j                  d||       d{   S 7 w)a  
        Get the next message if one is available, otherwise None.

        If timeout is specified, the system will wait for `timeout` seconds
        before returning. Timeout should be specified as a floating point
        number or None to wait indefinitely.
        get_message)r#  r$  Nr  )rO   r#  r$  s      rP   r&  zPubSub.get_messageH  s>      \\22HH&? I 
 
 	
 
   ,535g      ?)exception_handlerpoll_timeoutr)  c                n   K   | j                   j                  j                  |||        d{   S 7 w)a  Process pub/sub messages using registered callbacks.

        This is the equivalent of :py:meth:`redis.PubSub.run_in_thread` in
        redis-py, but it is a coroutine. To launch it as a separate task, use
        ``asyncio.create_task``:

            >>> task = asyncio.create_task(pubsub.run())

        To shut it down, use asyncio cancellation:

            >>> task.cancel()
            >>> await task
        )
sleep_timer(  r   N)r   rE   execute_pubsub_run)rO   r(  r)  s      rP   runz
PubSub.runX  s>     & \\22EE#7HQU F 
 
 	
 
r'  )rS   r   r
  )Fg        )r   r   r   r   r'   rQ   rX   rf   r^   propertyr   r  r!   r   r    r$   r#   r  r  r   r"  r   r   r&  r-  r   rR   rP   r   r     s    	7} 	7S FD F F
: 


,
8E
	

 

,
8E
	

 SV
)-
@H
& !	
 	

 

rR   r   )<rG   loggingtypingr   r   r   r   r   r   r	   &redis.asyncio.multidb.command_executorr
   redis.asyncio.multidb.configr   r   r   r   redis.asyncio.multidb.databaser   r   r   &redis.asyncio.multidb.failure_detectorr   !redis.asyncio.multidb.healthcheckr   r   redis.asyncio.retryr   redis.backgroundr   redis.backoffr   redis.commandsr   r   redis.multidb.circuitr   r   rr   redis.multidb.exceptionr   r   r   redis.observability.attributesr   redis.typingr    r!   r"   r#   r$   redis.utilsr%   	getLoggerr   r   r'   r   r   r   r   rR   rP   <module>r@     s      K K K I  N M G L % 0 # F 0 2 
 = P P $			8	$ IL,.? IL ILX& &C'): CLu
 u
rR   