
    phbH                     p   S SK r S SKrS SKJrJrJrJrJrJrJ	r	  S SK
Jr  S SKJr  S SKJrJr  S SKJrJr  S SKJr  S SKJrJr  S S	KJr  S S
KJrJr  S SKJr  S SKJ r!  S SK"J#r#J$r$  S SK%J&r&J'r'J(r(  S SK)J*r*  \RV                  " \,5      r-\* " S S\\5      5       r.S\4S jr/ " S S\\5      r0 " S S5      r1g)    N)Any	AwaitableCallable	CoroutineListOptionalUnion)PubSubHandler)DefaultCommandExecutor)DEFAULT_GRACE_PERIODMultiDbConfig)AsyncDatabase	Databases)AsyncFailureDetector)HealthCheckHealthCheckPolicy)BackgroundScheduler)AsyncCoreCommandsAsyncRedisModuleCommands)CircuitBreaker)State)NoValidDatabaseExceptionUnhealthyDatabaseException)ChannelT
EncodableTKeyT)experimentalc                   |   \ rS rSrSrS\4S jrS-S jrS rS r	S\
4S	 jrS
\SS4S jrS
\4S jrS\S\4S jrS
\4S jrS
\S\4S jrS\4S jrS\4S jrS rS rSSSS.S\S/\\\\   4   4   S\S\\   S \ S!\\   4
S" jjr!S# r" S.S$\\\#/\$\\S4   4      4S% jjr%S
\S\ 4S& jr&S'\'S(\(S)\(4S* jr)S+ r*S,r+g)/MultiDBClient   zl
Client that operates on multiple logical Redis databases.
Should be used in Active-Active database setups.
configc                    UR                  5       U l        UR                  5       U l        UR                  b%  U R                  R                  UR                  5        UR                  U l        UR                  R                  UR                  UR                  5      U l        UR                  5       U l        UR                  b%  U R                  R                  UR                  5        UR                   c  UR#                  5       OUR                   U l        U R$                  R'                  U R                  5        UR(                  U l        UR,                  U l        UR0                  U l        U R2                  R5                  [6        /5        [9        U R                  U R                  U R2                  U R$                  UR:                  UR<                  U R.                  U R*                  S9U l        SU l         [B        RD                  " 5       U l#        [I        5       U l%        Xl&        S U l'        / U l(        S U l)        g )N)failure_detectors	databasescommand_retryfailover_strategyfailover_attemptsfailover_delayevent_dispatcherauto_fallback_intervalF)*r$   
_databasesdefault_health_checks_health_checkshealth_checksextendhealth_check_interval_health_check_intervalhealth_check_policyvaluehealth_check_probeshealth_check_delay_health_check_policydefault_failure_detectors_failure_detectorsr#   r&   default_failover_strategy_failover_strategyset_databasesr*   _auto_fallback_intervalr)   _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     V/home/james-whalen/.local/lib/python3.13/site-packages/redis/asyncio/multidb/client.py__init__MultiDBClient.__init__   s    **,$::<+&&v';';<&,&B&B#7=7Q7Q7W7W&&(A(A8
! #)"B"B"D##/##**6+C+CD ''/ ,,.)) 	
 	--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                 d   #    U R                   (       d  U R                  5       I S h  vN   U $  N7fN)rB   
initializerK   s    rL   
__aenter__MultiDBClient.__aenter__I   s(     //### $s   %0.0c                    #    U R                   (       a  U R                   R                  5         U R                  (       a  U R                  R                  5         U R                   H  nUR                  5         M     g 7frR   )rH   cancelrJ   rI   )rK   exc_type	exc_value	tracebackhc_tasks        rL   	__aexit__MultiDBClient.__aexit__N   sS     ""##**,%%&&--/~~GNN &s   A;A=c                 4  #    S nU R                  US9I Sh  vN   [        R                  " U R                  R	                  U R
                  U R                   5      5      U l        SnU R                   H  u  p4UR                  R                  U R                  5        UR                  R                  [        R                  :X  d  MT  U(       a  M]  U R                  R                  U5      I Sh  vN   SnM     U(       d  [!        S5      eSU l        g N N&7f)zD
Perform initialization of databases to define their initial state.
c                    #    U e7frR    )errors    rL   raise_exception_on_failed_hc>MultiDBClient.initialize.<locals>.raise_exception_on_failed_hc[   s
     K   )on_errorNFTz4Initial connection failed - no active database found)_check_databases_healthrC   create_taskrF   run_recurring_asyncr1   rH   r+   circuiton_state_changed!_on_circuit_state_change_callbackstateCBStateCLOSEDrA   set_active_databaser   rB   )rK   rc   is_active_db_founddatabaseweights        rL   rS   MultiDBClient.initializeV   s     
	 **4P*QQQ #*"5"522++,,#
 # $H--d.T.TU %%7@R@R++??III%)" !0 "*F   5 	R$ Js.   DDB+DDD/D0%DDc                     U R                   $ )z5
Returns a sorted (by weight) list of all databases.
)r+   rT   s    rL   get_databasesMultiDBClient.get_databases{   s     rO   rr   Nc                   #    SnU R                    H  u  p4X1:X  d  M  Sn  O   U(       d  [        S5      eU R                  U5      I Sh  vN   UR                  R                  [
        R                  :X  aD  U R                   R                  S5      S   u  pTU R                  R                  U5      I Sh  vN   g[        S5      e N{ N7f)z<
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_healthrj   rm   rn   ro   	get_top_nrA   rp   r   )rK   rr   existsexisting_db_highest_weighted_dbs         rL   rp   !MultiDBClient.set_active_database   s      "ooNK& .
 NOO##H---!!W^^3%)__%>%>q%A!%D"'';;HEEE&?
 	
 	. Fs)   C	,C		C
A*C	4C5C	C	c                 L  #    U R                    H  u  p#X!:X  d  M  [        S5      e   U R                  U5      I Sh  vN   U R                   R                  S5      S   u  pEU R                   R	                  XR
                  5        U R                  X5      I Sh  vN   g Nc N7f)z+
Adds a new database to the database list.
zGiven database already existsNrz   r   )r+   r{   r|   r}   addrs   _change_active_database)rK   rr   r   r   r   highest_weights         rL   add_databaseMultiDBClient.add_database   s      #ooNK& !@AA . ##H---.2oo.G.G.J1.M+Hoo6**8III	 	. 	Js'   B$!B$B AB$B"B$"B$new_databasehighest_weight_databasec                    #    UR                   UR                   :  aM  UR                  R                  [        R                  :X  a$  U R
                  R                  U5      I S h  vN   g g g  N7frR   )rs   rj   rm   rn   ro   rA   rp   )rK   r   r   s      rL   r   %MultiDBClient._change_active_database   s_      "9"@"@@$$**gnn<'';;LIII = A Js   A!A-#A+$A-c                 *  #    U R                   R                  U5      nU R                   R                  S5      S   u  p4XB::  aM  UR                  R                  [
        R                  :X  a$  U R                  R                  U5      I Sh  vN   ggg N7f)z,
Removes a database from the database list.
rz   r   N)	r+   remover}   rj   rm   rn   ro   rA   rp   )rK   rr   rs   r   r   s        rL   remove_databaseMultiDBClient.remove_database   s      ''1.2oo.G.G.J1.M+ $#++11W^^C'';;<OPPP D % Qs   BB	B
Brs   c                 (  #    SnU R                    H  u  pEXA:X  d  M  Sn  O   U(       d  [        S5      eU R                   R                  S5      S   u  pgU R                   R                  X5        X!l        U R                  X5      I Sh  vN   g N7f)z,
Updates a database from the database list.
NTry   rz   r   )r+   r{   r}   update_weightrs   r   )rK   rr   rs   r~   r   r   r   r   s           rL   update_database_weight$MultiDBClient.update_database_weight   s      "ooNK& .
 NOO.2oo.G.G.J1.M+%%h7 **8IIIs   BA-B
BBfailure_detectorc                 :    U R                   R                  U5        g)z.
Adds a new failure detector to the database.
N)r8   append)rK   r   s     rL   add_failure_detector"MultiDBClient.add_failure_detector   s     	&&'78rO   healthcheckc                    #    U R                    ISh  vN   U R                  R                  U5        SSS5      ISh  vN   g N0 N! , ISh  vN  (       d  f       g= f7f)z*
Adds a new health check to the database.
N)rE   r-   r   )rK   r   s     rL   add_health_checkMultiDBClient.add_health_check   s3      ===&&{3 !=====sA   A"AA"AA"AA"A"AAAA"c                    #    U R                   (       d  U R                  5       I Sh  vN   U R                  R                  " U0 UD6I Sh  vN $  N( N7f)z2
Executes a single command and return its result.
N)rB   rS   rA   execute_commandrK   argsoptionss      rL   r   MultiDBClient.execute_command   sG      //###**::DLGLLL $Ls!   %AA#AAAAc                     [        U 5      $ )z*
Enters into pipeline mode of the client.
)PipelinerT   s    rL   pipelineMultiDBClient.pipeline   s     ~rO   F
shard_hintvalue_from_callablewatch_delayfuncr   watchesr   r   r   c                   #    U R                   (       d  U R                  5       I Sh  vN   U R                  R                  " U/UQ7UUUS.6I Sh  vN $  N. N7f)z#
Executes callable as transaction.
Nr   )rB   rS   rA   execute_transaction)rK   r   r   r   r   r   s         rL   transactionMultiDBClient.transaction   sc      //###**>>

 " 3#
 
 	
 $
s!   %AA)AAAAc                 x   #    U R                   (       d  U R                  5       I Sh  vN   [        U 40 UD6$  N7f)z
Return a Publish/Subscribe object. With this object, you can
subscribe to channels and listen for messages that get published to
them.
N)rB   rS   PubSub)rK   kwargss     rL   pubsubMultiDBClient.pubsub  s5      //###d%f%% $s   %:8:rf   c           	        #     U R                    VVs/ s H*  u  p#[        R                  " U R                  U5      5      PM,     snnU l        [        R
                  " [        R                  " U R                  SS06U R                  S9I Sh  vN nU H~  n[        U[        5      (       d  M  UR                  n[        R                  UR                  l        [         R#                  SUR$                  S9  U(       d  Ml  U" UR$                  5        M     gs  snnf  N! [        R                   a    [        R                  " S5      ef = f7f)zS
Runs health checks as a recurring task.
Runs health checks against all databases.
return_exceptionsT)timeoutNz4Health check execution exceeds health_check_intervalz%Health check failed, due to exception)exc_info)r+   rC   rh   r|   rI   wait_forgatherr1   TimeoutError
isinstancer   rr   rn   OPENrj   rm   logger	exceptionoriginal_exception)rK   rf   rr   r   resultsresultunhealthy_dbs          rL   rg   %MultiDBClient._check_databases_health  s#    	 $(??#2KH ##D$9$9($CD#2DN $,,^^&* 33 G F&"<==%-4\\$$*  ;#66 ! 
 8V667 ! ## 	&&F 	sG   ED 1DA	D DD E.AE ED +E

Ec                   #    U R                   R                  U R                  U5      I Sh  vN nU(       dI  UR                  R                  [
        R                  :w  a  [
        R                  UR                  l        U$ U(       aG  UR                  R                  [
        R                  :w  a  [
        R                  UR                  l        U$  N7f)z?
Runs health checks on the given database until first failure.
N)r6   executer-   rj   rm   rn   r   ro   )rK   rr   
is_healthys      rL   r|   MultiDBClient._check_db_health4  s     
  44<<
 

 %%5)0  &H,,22gnnD%,^^H"
s   *CCB%Crj   	old_state	new_statec                 J   [         R                  " 5       nU[        R                  :X  a5  [         R                  " U R                  UR                  5      5      U l        g U[        R                  :X  a1  U[        R                  :X  a  UR                  [        [        U5        g g g rR   )rC   get_running_looprn   	HALF_OPENrh   r|   rr   rJ   ro   r   
call_laterr   _half_open_circuit)rK   rj   r   r   loops        rL   rl   /MultiDBClient._on_circuit_state_change_callbackF  s~     '')))))0)<)<%%g&6&67*D& &9+DOO02DgN ,E&rO   c                    #    U R                   R                  (       a7  U R                   R                  R                  R                  5       I S h  vN   g g  N7frR   )rA   active_databaseclientacloserT   s    rL   r   MultiDBClient.acloseT  s@       00''77>>EEGGG 1Gs   AAAA)r<   rF   r>   rG   r+   r=   r:   r8   rJ   rE   rI   r1   r6   r-   rH   rA   rB   )rK   r   rP   r   rR   ),__name__
__module____qualname____firstlineno____doc__r   rM   rU   r]   rS   r   rv   r   rp   r   r   r   floatr   r   r   r   r   r   r   r   r	   r   r   r   r   strboolr   r   	Exceptionr   rg   r|   r   rn   rl   r   __static_attributes__ra   rO   rL   r   r      s   
**} **X
# Jy 
- 
D 
2J= JJ)JDQJQm QJ] JE J&95I 94+ 4M %)$)'+

|U3	#+>%??@
 
 SM	

 "
 e_
,	& PT$88YK3T>1J$JKL$8L}  $O%O29OFMOHrO   r   rj   c                 .    [         R                  U l        g rR   )rn   r   rm   )rj   s    rL   r   r   Y  s    %%GMrO   c                       \ rS rSrSrS\4S jrSS jrS rS r	S	 r
S\4S
 jrS\4S jrSS jrSS jrSS jrS rS\\   4S jrSrg)r   i]  z?
Pipeline implementation for multiple logical Redis databases.
r   c                     / U l         Xl        g rR   )_command_stack_client)rK   r   s     rL   rM   Pipeline.__init__b  s     rO   rP   c                    #    U $ 7frR   ra   rT   s    rL   rU   Pipeline.__aenter__f  
     re   c                    #    U R                  5       I S h  vN   U R                  R                  XU5      I S h  vN   g  N) N7frR   )resetr   r]   rK   rY   rZ   r[   s       rL   r]   Pipeline.__aexit__i  s6     jjlll$$X)DDD 	Ds   AA #AAAAc                 >    U R                  5       R                  5       $ rR   )_async_self	__await__rT   s    rL   r   Pipeline.__await__m  s    !++--rO   c                    #    U $ 7frR   ra   rT   s    rL   r   Pipeline._async_selfp  r   re   c                 ,    [        U R                  5      $ rR   )lenr   rT   s    rL   __len__Pipeline.__len__s  s    4&&''rO   c                     g)z1Pipeline instances should always evaluate to TrueTra   rT   s    rL   __bool__Pipeline.__bool__v  s    rO   Nc                    #    / U l         g 7frR   )r   rT   s    rL   r   Pipeline.resetz  s      s   	c                 @   #    U R                  5       I Sh  vN   g N7f)zClose the pipelineN)r   rT   s    rL   r   Pipeline.aclose}  s     jjl   c                 >    U R                   R                  X45        U $ )a:  
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      rL   pipeline_execute_command!Pipeline.pipeline_execute_command  s     	""D?3rO   c                 &    U R                   " U0 UD6$ )zAdds a command to the stack)r  rK   r   r   s      rL   r   Pipeline.execute_command  s    ,,d=f==rO   c                 ~  #    U R                   R                  (       d"  U R                   R                  5       I Sh  vN    U R                   R                  R	                  [        U R                  5      5      I Sh  vN U R                  5       I Sh  vN   $  N] N N	! U R                  5       I Sh  vN    f = f7f)z0Execute all the commands in the current pipelineN)r   rB   rS   rA   execute_pipelinetupler   r   rT   s    rL   r   Pipeline.execute  s     ||'',,))+++	66GGd))*  **, , $**,sW   9B=BB=;B <B=B  B=BB=B B=B:3B64B::B=)r   r   )rK   r   rP   r   rP   N)rP   r   )r   r   r   r   r   r   rM   rU   r]   r   r   intr   r   r   r   r   r  r   r   r   r   r   ra   rO   rL   r   r   ]  sd    } E.( ($ !>
tCy 
rO   r   c                       \ rS rSrSrS\4S jrSS jrSS jrS	 r	\
S\4S
 j5       rS\4S jrS\S\4S jrS\4S jrS\S\4S jrS r SS\S\\   4S jjrSSS.S\SS4S jjrSrg)r   i  z*
PubSub object for multi database client.
r   c                 \    Xl         U R                   R                  R                  " S0 UD6  g)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
Nra   )r   rA   r   )rK   r   r   s      rL   rM   PubSub.__init__  s$     %%,,6v6rO   rP   c                    #    U $ 7frR   ra   rT   s    rL   rU   PubSub.__aenter__  r   re   Nc                 @   #    U R                  5       I S h  vN   g  N7frR   )r   r   s       rL   r]   PubSub.__aexit__  s     kkmr  c                 h   #    U R                   R                  R                  S5      I S h  vN $  N7f)Nr   r   rA   execute_pubsub_methodrT   s    rL   r   PubSub.aclose  s&     \\22HHRRRR   )202c                 V    U R                   R                  R                  R                  $ rR   )r   rA   active_pubsub
subscribedrT   s    rL   r  PubSub.subscribed  s    ||,,::EEErO   r   c                 l   #    U R                   R                  R                  " S/UQ76 I S h  vN $  N7f)Nr   r  rK   r   s     rL   r   PubSub.execute_command  s7     \\22HH
 $
 
 	
 
   +424r   c                 r   #    U R                   R                  R                  " S/UQ70 UD6I Sh  vN $  N7f)a  
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      rL   r#  PubSub.psubscribe  sA      \\22HH

#)
 
 	
 
   .757c                 l   #    U R                   R                  R                  " S/UQ76 I Sh  vN $  N7f)zR
Unsubscribe from the supplied patterns. If empty, unsubscribe from
all patterns.
punsubscribeNr  r  s     rL   r'  PubSub.punsubscribe  s9     
 \\22HH
!
 
 	
 
r!  c                 r   #    U R                   R                  R                  " S/UQ70 UD6I Sh  vN $  N7f)a"  
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      rL   r*  PubSub.subscribe  sA      \\22HH

"(
 
 	
 
r%  c                 l   #    U R                   R                  R                  " S/UQ76 I Sh  vN $  N7f)zQ
Unsubscribe from the supplied channels. If empty, unsubscribe from
all channels
unsubscribeNr  r  s     rL   r-  PubSub.unsubscribe  s9     
 \\22HH
 
 
 	
 
r!  ignore_subscribe_messagesr   c                 h   #    U R                   R                  R                  SUUS9I Sh  vN $  N7f)z
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  )rK   r/  r   s      rL   r1  PubSub.get_message  s=      \\22HH&? I 
 
 	
 
r  g      ?)exception_handlerpoll_timeoutr4  c                f   #    U R                   R                  R                  X!U S9I Sh  vN $  N7f)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_timer3  r   N)r   rA   execute_pubsub_run)rK   r3  r4  s      rL   run
PubSub.run  s:     & \\22EE#QU F 
 
 	
 
s   (1/1)r   )rP   r   r  )Fg        )r   r   r   r   r   r   rM   rU   r]   r   propertyr   r  r   r   r   r
   r#  r'  r   r*  r-  r   r   r1  r8  r   ra   rO   rL   r   r     s    	7} 	7S FD F F
: 



h 

- 


 


X 

 


 SV
)-
@H
& !	
 	

 

 
rO   r   )2rC   loggingtypingr   r   r   r   r   r   r	   redis.asyncio.clientr
   &redis.asyncio.multidb.command_executorr   redis.asyncio.multidb.configr   r   redis.asyncio.multidb.databaser   r   &redis.asyncio.multidb.failure_detectorr   !redis.asyncio.multidb.healthcheckr   r   redis.backgroundr   redis.commandsr   r   redis.multidb.circuitr   r   rn   redis.multidb.exceptionr   r   redis.typingr   r   r   redis.utilsr   	getLoggerr   r   r   r   r   r   ra   rO   rL   <module>rJ     s      M M M . I L C G L 0 F 0 2 X 3 3 $			8	$ H,.? H HD
& &A'): AHq
 q
rO   