
    /
iU                        d dl Z d dlZd dlmZ d dlmZ d dlmZmZ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 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&m'Z'm(Z( d dl)m*Z* d dl+m,Z,m-Z- d dl.m/Z/ d dl0m1Z1 d dl2m3Z3  e j4        e5          Z6e3 G d dee                      Z7defdZ8 G d dee          Z9 G d d          Z:dS )    N)as_completed)ThreadPoolExecutor)AnyCallableListOptional)BackgroundScheduler)	NoBackoff)PubSubWorkerThread)CoreCommandsRedisModuleCommands)MaintNotificationsConfig)CircuitBreaker)State)DefaultCommandExecutor)DEFAULT_GRACE_PERIODDatabaseConfigInitialHealthCheckMultiDbConfig)Database	DatabasesSyncDatabase)InitialHealthCheckFailedErrorNoValidDatabaseExceptionUnhealthyDatabaseException)FailureDetector)HealthCheckHealthCheckPolicy)GeoFailoverReason)Retry)experimentalc                      e Zd ZdZdef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edgdf         fdZd Zde	defdZdeeef         fdZd Zd e d!e!d"e!fd#Z"d$ Z#dS )&MultiDBClientz
    Client that operates on multiple logical Redis databases.
    Should be used in Client-side geographic failover database setups.
    configc           
      N   |                                 | _        |j        s|                                n|j        | _        |j        | _        |j                            |j	        |j
                  | _        |j        s|                                n|j        | _        |j        |                                n|j        | _        | j                            | j                   |j        | _        |j        | _        |j        | _        | j                            t4          f           t7          | j        | j        | j        | j        |j        |j        | j        | j                  | _        d| _        tA          j!                    | _"        tG                      | _$        || _%        d S )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_probeshealth_check_probes_delay_health_check_policyr&   default_failure_detectors_failure_detectorsr)   default_failover_strategy_failover_strategyset_databasesr-   _auto_fallback_intervalr,   _event_dispatcherr(   _command_retryupdate_supported_errorsConnectionRefusedErrorr   r*   r+   command_executorinitialized	threadingRLock_hc_lockr	   _bg_scheduler_config)selfr$   s     C:\Users\Dell Inspiron 16\Desktop\tws\AgrotaPowerBi\back-agrota-powerbi\mcp-client-agrota\venv\Lib\site-packages\redis/multidb/client.py__init__zMultiDBClient.__init__+   s    **,, '&F((***% 	
 '-&B#7=7Q7W7W&(H8
 8
!
 +*F,,...) 	 '/ ,,...) 	
 	--do>>>'-'D$!'!8$2335K4MNNN 6"5o-"5$6!0!3#'#?	!
 	!
 	!
 !!))022    c                 X   |                                   | j                            | j        | j                   d}| j        D ]N\  }}|j                            | j                   |j        j	        t          j        k    r|s|| j        _        d}O|st          d          d| _        dS )zT
        Perform initialization of databases to define their initial state.
        FTz4Initial connection failed - no active database foundN)_perform_initial_health_checkrH   run_recurringr3   _check_databases_healthr.   circuiton_state_changed!_on_circuit_state_change_callbackstateCBStateCLOSEDrC   _active_databaser   rD   )rJ   is_active_db_founddatabaseweights       rK   
initializezMultiDBClient.initializeU   s     	**,,, 	(('(	
 	
 	

 # $ 		* 		*Hf--d.TUUU %77@R7 :B%6%)"! 	*F    rM   returnc                     | j         S )zE
        Returns a sorted (by weight) list of all databases.
        )r.   rJ   s    rK   get_databaseszMultiDBClient.get_databasesw   s     rM   rZ   Nc                 L   d}| j         D ]\  }}||k    rd} n|st          d          |                     |           |j        j        t
          j        k    r=| j                             d          d         \  }}|t          j	        f| j
        _        dS t          d          )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)r.   
ValueError_check_db_healthrR   rU   rV   rW   	get_top_nr   MANUALrC   active_databaser   )rJ   rZ   existsexisting_db_highest_weighted_dbs         rK   set_active_databasez!MultiDBClient.set_active_database}   s     "o 	 	NKh&& '  	PNOOOh'''!W^33%)_%>%>q%A%A!%D"!(5D!1 F&?
 
 	
rM   Tskip_initial_health_checkc                 \   t          dt                                |j        d<   d|j        vrt          d          |j        d<   |j        r# | j        j        j        |j        fi |j        }ny|j        r[|j                            t          dt                                           | j        j                            |j                  }n | j        j        di |j        }|j	        |
                                n|j	        }t          |||j        |j        	          }	 |                     |           n# t          $ r |s Y nw xY w| j                            d
          d         \  }}| j                            ||j                   |                     ||           dS )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.
        r   )retriesbackoffretrymaint_notifications_configF)enabled)connection_poolN)clientrR   r[   health_check_urlrc    )r    r
   client_kwargsr   from_urlrI   client_class	from_pool	set_retryrR   default_circuit_breakerr   r[   rw   re   r   r.   rf   add_change_active_database)rJ   r$   rn   rv   rR   rZ   rl   highest_weights           rK   add_databasezMultiDBClient.add_database   s    ).a(M(M(MW% (v/CCC(777  !=> ? 
	G7T\.7 #)#7 FF  	G&&uQ	'L'L'LMMM\.88 & 0 9  FF /T\.FF1EFFF ~% **,,, 	 =#4	
 
 
	!!(++++) 	 	 	,  	 /3o.G.G.J.J1.M+^Hho666$$X/BCCCCCs   *E   EEnew_databasehighest_weight_databasec                     |j         |j         k    r4|j        j        t          j        k    r|t
          j        f| j        _        d S d S d S N)	r[   rR   rU   rV   rW   r   	AUTOMATICrC   rh   )rJ   r   r   s      rK   r   z%MultiDBClient._change_active_database   sV     "9"@@@$*gn<< !+5D!111 A@<<rM   c                     | j                             |          }| j                             d          d         \  }}||k    r4|j        j        t
          j        k    r|t          j        f| j	        _
        dS dS dS )z<
        Removes a database from the database list.
        rc   r   N)r.   removerf   rR   rU   rV   rW   r   rg   rC   rh   )rJ   rZ   r[   rl   r   s        rK   remove_databasezMultiDBClient.remove_database   s     ''11.2o.G.G.J.J1.M+^ f$$#+1W^CC $!(5D!111 %$CCrM   r[   c                    d}| j         D ]\  }}||k    rd} n|st          d          | j                             d          d         \  }}| j                             ||           ||_        |                     ||           dS )z<
        Updates a database from the database list.
        NTrb   rc   r   )r.   rd   rf   update_weightr[   r   )rJ   rZ   r[   ri   rj   rk   rl   r   s           rK   update_database_weightz$MultiDBClient.update_database_weight   s     "o 	 	NKh&& '  	PNOOO.2o.G.G.J.J1.M+^%%h777 $$X/BCCCCCrM   failure_detectorc                 :    | j                             |           dS )z>
        Adds a new failure detector to the database.
        N)r:   append)rJ   r   s     rK   add_failure_detectorz"MultiDBClient.add_failure_detector   s"     	&&'788888rM   healthcheckc                 z    | j         5  | j                            |           ddd           dS # 1 swxY w Y   dS )z:
        Adds a new health check to the database.
        N)rG   r1   r   )rJ   r   s     rK   add_health_checkzMultiDBClient.add_health_check  s     ] 	4 	4&&{333	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4s   044c                 \    | j         s|                                   | j        j        |i |S )zB
        Executes a single command and return its result.
        )rD   r\   rC   execute_commandrJ   argsoptionss      rK   r   zMultiDBClient.execute_command  s:      	OO4t$4dFgFFFrM   c                      t          |           S )z:
        Enters into pipeline mode of the client.
        )Pipeliner_   s    rK   pipelinezMultiDBClient.pipeline  s     ~~rM   funcr   c                 b    | j         s|                                   | j        j        |g||R  S )z3
        Executes callable as transaction.
        )rD   r\   rC   execute_transaction)rJ   r   watchesr   s       rK   transactionzMultiDBClient.transaction  sB      	OO8t$8RR'RRRRrM   c                 R    | j         s|                                  t          | fi |S )z
        Return a Publish/Subscribe object. With this object, you can
        subscribe to channels and listen for messages that get published to
        them.
        )rD   r\   PubSub)rJ   kwargss     rK   pubsubzMultiDBClient.pubsub%  s5      	OOd%%f%%%rM   c                    | j                             | j        |          }|s2|j        j        t
          j        k    rt
          j        |j        _        |S |r0|j        j        t
          j        k    rt
          j        |j        _        |S )zO
        Runs health checks on the given database until first failure.
        )r8   executer1   rR   rU   rV   OPENrW   )rJ   rZ   
is_healthys      rK   re   zMultiDBClient._check_db_health0  sz    
 .66t7JHUU
 	4%55)0 & 	4H,2gnDD%,^H"rM   c                     t          t           j                            5  fd j        D             }i }	 t          | j                  D ]|}	 ||         }|                                ||<   ## t          $ rM}|j        }t          j	        |j
        _        t                              d|j                   d||<   Y d}~ud}~ww xY wn# t          $ r t          d          w xY w	 ddd           n# 1 swxY w Y   |S )	zk
        Runs health checks as a recurring task.
        Runs health checks against all databases.
        )max_workersc                 N    i | ]!\  }}                     j        |          |"S rx   )submitre   ).0rZ   rk   executorrJ   s      rK   
<dictcomp>z9MultiDBClient._check_databases_health.<locals>.<dictcomp>G  s@       Ha  5x@@(  rM   )timeoutz%Health check failed, due to exception)exc_infoFNz4Health check execution exceeds health_check_interval)r   lenr.   r   r3   resultr   rZ   rV   r   rR   rU   loggerdebugoriginal_exceptionTimeoutError)rJ   futuresresultsfuturerZ   eunhealthy_dbr   s   `      @rK   rQ   z%MultiDBClient._check_databases_health@  s   
  C,@,@AAA 	X    #'?  G
 G*T%@   6 6F6#*6?,2MMOO))5 	6 	6 	6'(z5<\,2C%&%9 %   
 16------	66      "J  !6	 	 	 	 	 	 	 	 	 	 	 	 	 	 	< sS   C;CA65C6
C ACCCCC;C++C;;C?C?c                    |                                  }d}| j        j        t          j        k    rd|                                v}n| j        j        t          j        k    r6t          |                                          t          |          dz  k    }n0| j        j        t          j	        k    rd|                                v }|st          d| j        j                   dS )zj
        Runs initial health check and evaluate healthiness based on initial_health_check_policy.
        TF   z:Initial health check failed. Initial health check policy: N)rQ   rI   initial_health_check_policyr   ALL_AVAILABLEvaluesMAJORITY_AVAILABLEsumr   ONE_AVAILABLEr   )rJ   r   r   s      rK   rO   z+MultiDBClient._perform_initial_health_checke  s     ..00
<37I7WWWgnn&6&66JJL4!45 5 W^^--..W1AAJJL48J8XXX!1!11J 	/wT\Muww  	 	rM   rR   	old_state	new_statec                    |t           j        k    r|                     |j                   d S |t           j        k    rY|t           j        k    rIt                              d|j         d           | j        	                    t          t          |           |t           j        k    r5|t           j        k    r't                              d|j         d           d S d S d S )Nz	Database z- is unreachable. Failover has been initiated.z is reachable again.)rV   	HALF_OPENre   rZ   rW   r   r   warningrH   run_oncer   _half_open_circuitinfo)rJ   rR   r   r   s       rK   rT   z/MultiDBClient._on_circuit_state_change_callback}  s     )))!!'"2333F&&9+D+DNN[G,[[[   ''$&8'   &&9+F+FKKJG$4JJJKKKKK '&+F+FrM   c                     | j         r| j                                          | j        j        r%| j        j        j                                         dS dS )z:
        Closes the client and all its resources.
        N)rH   stoprC   rh   rv   closer_   s    rK   r   zMultiDBClient.close  s`      	&##%%% 0 	A!18>>@@@@@	A 	ArM   )T)$__name__
__module____qualname____doc__r   rL   r\   r   r`   r   rm   r   boolr   r   r   r   floatr   r   r   r   r   r   r   r   r   r   re   dictrQ   rO   r   rV   rT   r   rx   rM   rK   r#   r#   $   sU        
(} ( ( ( (T        Dy    
L 
T 
 
 
 
: IM6D 6D$6DAE6D 6D 6D 6Dp
(
CO
 
 
 
     D| DU D D D D&9_ 9 9 9 94K 4 4 4 4G G G  S*t); < S S S S	& 	& 	& $     #hn)= # # # #J  0L%L29LFML L L L&A A A A ArM   r#   rR   c                 (    t           j        | _        d S r   )rV   r   rU   )rR   s    rK   r   r     s    %GMMMrM   c                       e Zd ZdZdefdZd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d
S )r   zG
    Pipeline implementation for multiple logical Redis databases.
    rv   c                 "    g | _         || _        d S r   )_command_stack_client)rJ   rv   s     rK   rL   zPipeline.__init__  s     rM   r]   c                     | S r   rx   r_   s    rK   	__enter__zPipeline.__enter__      rM   c                 .    |                                   d S r   reset)rJ   exc_type	exc_value	tracebacks       rK   __exit__zPipeline.__exit__      

rM   c                 R    	 |                                   d S # t          $ r Y d S w xY wr   r   	Exceptionr_   s    rK   __del__zPipeline.__del__  s:    	JJLLLLL 	 	 	DD	    
&&c                 *    t          | j                  S r   )r   r   r_   s    rK   __len__zPipeline.__len__  s    4&'''rM   c                     dS )z1Pipeline instances should always evaluate to TrueTrx   r_   s    rK   __bool__zPipeline.__bool__  s    trM   Nc                     g | _         d S r   )r   r_   s    rK   r   zPipeline.reset  s     rM   c                 .    |                                   dS )zClose the pipelineNr   r_   s    rK   r   zPipeline.close  s    

rM   c                 >    | 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      rK   pipeline_execute_commandz!Pipeline.pipeline_execute_command  s$     	""D'?333rM   c                      | j         |i |S )zAdds a command to the stack)r   rJ   r   r   s      rK   r   zPipeline.execute_command  s    ,t,d=f===rM   c                 
   | j         j        s| j                                          	 | j         j                            t          | j                            |                                  S # |                                  w xY w)z0Execute all the commands in the current pipeline)r   rD   r\   rC   execute_pipelinetupler   r   r_   s    rK   r   zPipeline.execute  sq    |' 	&L##%%%	<0AAd)**  JJLLLLDJJLLLLs   0A, ,B)r]   r   r]   N)r   r   r   r   r#   rL   r   r   r   intr   r   r   r   r   r   r   r   r   r   rx   rM   rK   r   r     s        }           ( ( ( ( ($    ! ! ! !      > > >
c 
 
 
 
 
 
rM   r   c                       e Zd ZdZdefdZddZddZddZdd	Z	e
defd
            Zd Zd Zd Zd Zd Zd Zd Z	 d dedefdZ	 d dedefdZ	 	 	 	 d!dededee         deddf
dZdS )"r   z2
    PubSub object for multi database client.
    rv   c                 B    || _          | j         j        j        di | dS )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
        Nrx   )r   rC   r   )rJ   rv   r   s      rK   rL   zPubSub.__init__  s/     ,%,66v66666rM   r]   c                     | S r   rx   r_   s    rK   r   zPubSub.__enter__  r   rM   Nc                 R    	 |                                   d S # t          $ r Y d S w xY wr   r   r_   s    rK   r   zPubSub.__del__  s<    	 JJLLLLL 	 	 	DD	r   c                 @    | j         j                            d          S )Nr   r   rC   execute_pubsub_methodr_   s    rK   r   zPubSub.reset  s    |,BB7KKKrM   c                 .    |                                   d S r   r   r_   s    rK   r   zPubSub.close   r   rM   c                 .    | j         j        j        j        S r   )r   rC   active_pubsub
subscribedr_   s    rK   r  zPubSub.subscribed  s    |,:EErM   c                 2     | j         j        j        dg|R  S )Nr   r  rJ   r   s     rK   r   zPubSub.execute_command  s.    Bt|,B
 $
 
 
 	
rM   c                 8     | j         j        j        dg|R i |S )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()``.
        
psubscriber  r   s      rK   r
  zPubSub.psubscribe  >     Ct|,B

 
 
#)
 
 	
rM   c                 2     | j         j        j        dg|R  S )zj
        Unsubscribe from the supplied patterns. If empty, unsubscribe from
        all patterns.
        punsubscriber  r  s     rK   r  zPubSub.punsubscribe  1    
 Ct|,B
!
 
 
 	
rM   c                 8     | j         j        j        dg|R i |S )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()``.
        	subscriber  r   s      rK   r  zPubSub.subscribe!  s>     Ct|,B

 
 
"(
 
 	
rM   c                 2     | j         j        j        dg|R  S )zi
        Unsubscribe from the supplied channels. If empty, unsubscribe from
        all channels
        unsubscriber  r  s     rK   r  zPubSub.unsubscribe-  s&    
 Ct|,B=XSWXXXXrM   c                 8     | j         j        j        dg|R i |S )az  
        Subscribes the client to the specified shard 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_sharded_message()``.
        
ssubscriber  r   s      rK   r  zPubSub.ssubscribe4  r  rM   c                 2     | j         j        j        dg|R  S )zu
        Unsubscribe from the supplied shard_channels. If empty, unsubscribe from
        all shard_channels
        sunsubscriber  r  s     rK   r  zPubSub.sunsubscribe@  r  rM   F        ignore_subscribe_messagesr   c                 F    | j         j                            d||          S )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   r  rJ   r  r   s      rK   r  zPubSub.get_messageI  s0     |,BB&? C 
 
 	
rM   c                 F    | j         j                            d||          S )a&  
        Get the next message if one is available in a sharded channel, 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_sharded_messager  r  r  s      rK   r  zPubSub.get_sharded_messageY  s0     |,BB!&? C 
 
 	
rM   
sleep_timedaemonexception_handlersharded_pubsubr   c                 J    | j         j                            |||| |          S )N)r   r!  r   r"  )r   rC   execute_pubsub_run)rJ   r  r   r!  r"  s        rK   run_in_threadzPubSub.run_in_threadi  s6     |,??/) @ 
 
 	
rM   )r]   r   r   )Fr  )r  FNF)r   r   r   r   r#   rL   r   r   r   r   propertyr   r  r   r
  r  r  r  r  r  r   r  r  r   r   r%  rx   rM   rK   r   r     s        	7} 	7 	7 	7 	7      L L L L    FD F F F XF
 
 



 

 


 
 


 

 

Y Y Y

 

 


 
 
 IL
 
)-
@E
 
 
 
" IL
 
)-
@E
 
 
 
$  04$
 

 
 $H-	

 
 

 
 
 
 
 
rM   r   );loggingrE   concurrent.futuresr   concurrent.futures.threadr   typingr   r   r   r   redis.backgroundr	   redis.backoffr
   redis.clientr   redis.commandsr   r   redis.maint_notificationsr   redis.multidb.circuitr   r   rV   redis.multidb.command_executorr   redis.multidb.configr   r   r   r   redis.multidb.databaser   r   r   redis.multidb.exceptionr   r   r   redis.multidb.failure_detectorr   redis.multidb.healthcheckr   r   redis.observability.attributesr   redis.retryr    redis.utilsr!   	getLoggerr   r   r#   r   r   r   rx   rM   rK   <module>r;     s        + + + + + + 8 8 8 8 8 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 # # # # # # + + + + + + < < < < < < < < > > > > > > 0 0 0 0 0 0 2 2 2 2 2 2 A A A A A A            E D D D D D D D D D         
 ; : : : : : D D D D D D D D < < < < < <       $ $ $ $ $ $		8	$	$ rA rA rA rA rA' rA rA rAj& & & & &@ @ @ @ @"L @ @ @FU
 U
 U
 U
 U
 U
 U
 U
 U
 U
rM   