
    inE                     d   U d dl Z d dlZd dlZd dlmZmZ d dlmZ d dlm	Z	m
Z
mZmZ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  d dl!m"Z" eeef         Z#dede$fdZ%de&dede&fdZ'dZ(dZ)dZ*dZ+dZ, ej-        e.          Z/ G d de          Z0 G d de          Z1 G d de1          Z2 G d de2          Z3 G d de2          Z4 G d d e2          Z5 G d! d"e          Z6e6j7        Z8e6e9d#<    G d$ d%e0          Z: G d& d'e:          Z; G d( d)e:          Z<dS )*    N)ABCabstractmethod)Enum)ListOptionalTupleTypeUnion)Redis)RedisCluster)DEFAULT_TIMEOUTAsyncHTTPClientWrapper)	NoBackoff)
HttpClient)UnhealthyDatabaseException)Retryclsreturnc                     t          j        | j                  }t          d |j                                        D                       S )z7Extract parameter names from a class's __init__ method.c              3   ~   K   | ]8\  }}|d k    r-|j         t          j        j        t          j        j        fv 4|V  9dS )selfN)kindinspect	ParameterPOSITIONAL_OR_KEYWORDKEYWORD_ONLY).0nameparams      s/Users/user/workspace/sujinbaek/cqa-test-app/venv/lib/python3.11/site-packages/redis/asyncio/multidb/healthcheck.py	<genexpr>z#_get_init_params.<locals>.<genexpr>   si       	 	D%6>>J3*

 
 	
 
 
 
		 	    )r   	signature__init__	frozenset
parametersitems)r   sigs     r    _get_init_paramsr)      sP    

CL
)
)C 	 	>//11	 	 	 	 	 	r"   kwargsc                 b    t          |          fd|                                 D             S )zJFilter kwargs to only include parameters accepted by the class's __init__.c                 $    i | ]\  }}|v 	||S  r-   )r   kvalloweds      r    
<dictcomp>z"_filter_kwargs.<locals>.<dictcomp>(   s$    <<<TQqG||Aq|||r"   )r)   r'   )r*   r   r0   s     @r    _filter_kwargsr2   %   s2    s##G<<<<V\\^^<<<<r"         g      ?i  c                       e Zd ZdZeedefd                        Zeedefd                        Z	eedefd                        Z
ededefd            ZdS )	HealthCheckz!
    Health check interface.
    r   c                     dS )z*Number of probes to execute health checks.Nr-   r   s    r    health_check_probeszHealthCheck.health_check_probes9   	     	r"   c                     dS )z"Delay between health check probes.Nr-   r8   s    r    health_check_delayzHealthCheck.health_check_delay?   r:   r"   c                     dS )zCTimeout for the full health check operation (including all probes).Nr-   r8   s    r    health_check_timeoutz HealthCheck.health_check_timeoutE   r:   r"   	hc_clientc                 
   K   dS )ap  
        Function to determine the health status.

        Args:
            database: The database being checked
            hc_client: A Redis client (AsyncRedis or AsyncRedisCluster) to use for
                health checks. This client follows topology changes automatically.

        Returns:
            True if the database is healthy, False otherwise.
        Nr-   r   databaser?   s      r    check_healthzHealthCheck.check_healthK   s       	r"   N)__name__
__module____qualname____doc__propertyr   intr9   floatr<   r>   AsyncRedisClientTboolrC   r-   r"   r    r6   r6   4   s          S    ^ X E    ^ X e    ^ X 6G D    ^  r"   r6   c                       e Zd ZdZedee         defd            Zededefd            Z	ede
fd            Zed
d	            ZdS )HealthCheckPolicyz)
    Health checks execution policy.
    health_checksr   c                 
   K   dS )z8Execute health checks and return database health status.Nr-   )r   rO   rB   s      r    executezHealthCheckPolicy.execute`          	r"   health_checkc                 
   K   dS z?
        Executes health check against given database.
        Nr-   r   rS   rB   s      r    _executezHealthCheckPolicy._executee         
 	r"   c                 
   K   dS )z=
        Get a health check client for the database.
        Nr-   )r   rB   s     r    
get_clientzHealthCheckPolicy.get_clientl   rX   r"   Nc                 
   K   dS )Close all health check clients.Nr-   r8   s    r    closezHealthCheckPolicy.closes   rR   r"   r   N)rD   rE   rF   rG   r   r   r6   rL   rQ   rW   rK   rZ   r]   r-   r"   r    rN   rN   [   s          4+< 4    ^ ; T    ^ ,=    ^    ^  r"   rN   c                   h    e Zd ZdZd Zdee         defdZde	fdZ
ddZed	edefd
            ZdS )AbstractHealthCheckPolicyz'
    Abstract health check policy.
    c                     i | _         d S N)_clientsr8   s    r    r$   z"AbstractHealthCheckPolicy.__init__~   s    68r"   rO   r   c                     K   dt           f fdt          j        fd|D             ddi d{V }|D ]-}t          |t                    rt          d|          |s dS .dS )	a  
        Execute all health checks concurrently with individual timeouts.
        Each health check runs with its own timeout, and all run in parallel.

        All exception handling is centralized here - _execute() methods just
        propagate exceptions naturally.
        rS   c                 r   K   t          j                            |           | j                   d {V S )N)timeout)asynciowait_forrW   r>   )rS   rB   r   s    r    execute_with_timeoutz?AbstractHealthCheckPolicy.execute.<locals>.execute_with_timeout   sV       )lH55$9         r"   c                 &    g | ]} |          S r-   r-   )r   hcri   s     r    
<listcomp>z5AbstractHealthCheckPolicy.execute.<locals>.<listcomp>   s%    ???2""2&&???r"   return_exceptionsTNzUnhealthy databaseF)r6   rg   gather
isinstance	Exceptionr   )r   rO   rB   resultsresultri   s   ` `  @r    rQ   z!AbstractHealthCheckPolicy.execute   s      	[ 	 	 	 	 	 	 	  ???????
"
 
 
 
 
 
 
 
  	 	F&),, 01ExQWXXX uu tr"   c           
      ,  K   t          |          }| j                            |          }|et          |j        t
          t          f          r;|j                                        }t          |t
                    }t          di |}nt          |j        t          t          f          r|j                                                                        }t          |t                    }|j        j        }|r]|d         }t          d|j        |j        |j        j        j        |j        j        j        |j        j        j        |j        j        d|}n3t)          d          t+          dt-          |j                             || j        |<   |S )a  
        Get or create a health check client for the database.

        Creates a single client instance per database that follows topology
        changes automatically. For cluster databases, the client handles
        node discovery and slot mapping internally.
        Nr   )hostportdynamic_startup_nodesaddress_remaprequire_full_coverageretryz?Cluster client has no nodes - cannot create health check clientzUnsupported client type: r-   )idrc   getro   client
AsyncRedis	SyncRedisget_connection_kwargsr2   AsyncRedisClusterSyncRedisClustercopystartup_nodesrt   ru   nodes_manager_dynamic_startup_nodesrw   _require_full_coveragery   
ValueError	TypeErrortype)r   rB   db_idr|   conn_kwargsfiltered_kwargsr   
first_nodes           r    rZ   z$AbstractHealthCheckPolicy.get_client   s      8""5))>(/J	+BCC U&oCCEE"0j"I"I#66o66HO.?AQ-RSS U 'oCCEEJJLL"0>O"P"P ( =  !.q!1J. '_'_.6o.K.b&.o&C&Q.6o.K.b&o3  * FF %Y     SD<Q<Q S STTT#)DM% r"   Nc                    K   d | j                                         D             }|rt          j        |ddi d{V  | j                                          dS )r\   c                 Z    g | ](}t          j        |                                          )S r-   )rg   create_taskaclose)r   r|   s     r    rl   z3AbstractHealthCheckPolicy.close.<locals>.<listcomp>   s8     
 
 
5;G00
 
 
r"   rm   TN)rc   valuesrg   rn   clear)r   close_taskss     r    r]   zAbstractHealthCheckPolicy.close   s~      
 
?C}?S?S?U?U
 
 
  	G.+FFFFFFFFFFr"   rS   c                 
   K   dS rU   r-   rV   s      r    rW   z"AbstractHealthCheckPolicy._execute   rX   r"   r^   )rD   rE   rF   rG   r$   r   r6   rL   rQ   rK   rZ   r]   r   rW   r-   r"   r    r`   r`   y   s         9 9 94+< 4    B+,= + + + +Z	 	 	 	 ; T    ^  r"   r`   c                   "    e Zd ZdZdedefdZdS )HealthyAllPolicyzM
    Policy that returns True if all health check probes are successful.
    rS   r   c                   K   |                      |           d{V }|j        }t          |          D ]K}|                    ||           d{V }|s dS ||dz
  k     rt	          j        |j                   d{V  LdS )
        Executes health check against given database.

        Uses a single client that handles topology changes automatically.
        NF   T)rZ   r9   rangerC   rg   sleepr<   )r   rS   rB   r|   probesattemptrr   s          r    rW   zHealthyAllPolicy._execute   s       x000000001V}} 	E 	EG'44XvFFFFFFFFF uu!##mL$CDDDDDDDDDtr"   NrD   rE   rF   rG   r6   rL   rW   r-   r"   r    r   r      s@         ; T      r"   r   c                   "    e Zd ZdZdedefdZdS )HealthyMajorityPolicya3  
    Policy that returns True if a majority of health check probes are successful.

    Majority means more than half must pass:
    - 3 probes: need 2+ to pass (1 failure allowed)
    - 4 probes: need 3+ to pass (1 failure allowed, tie = unhealthy)
    - 5 probes: need 3+ to pass (2 failures allowed)
    rS   r   c                 ~  K   |j         }|dz
  dz  }|                     |           d{V }d}t          |          D ]~}	 |                    ||           d{V }|s|dz  }|dk     r dS n&# t          $ r}	|	}|dz  }|dk     r|Y d}	~	nd}	~	ww xY w||dz
  k     rt          j        |j                   d{V  dS )r   r      Nr   FTr9   rZ   r   rC   rp   rg   r   r<   )
r   rS   rB   r   allowed_unsuccessful_probesr|   last_exceptionr   rr   es
             r    rW   zHealthyMajorityPolicy._execute  s?      1 (.za&7#x00000000V}} 	E 	EG)+886JJJJJJJJ %/14/2Q66$uu ) ) )!"+q0+.22(( 32222	) !##mL$CDDDDDDDDDts   )A..
B8BBNr   r-   r"   r    r   r      s@         ; T      r"   r   c                   "    e Zd ZdZdedefdZdS )HealthyAnyPolicyzT
    Policy that returns True if at least one health check probe is successful.
    rS   r   c                 F  K   |j         }d}|                     |           d{V }t          |          D ]f}	 |                    ||           d{V }|r dS n# t          $ r}|}Y d}~nd}~ww xY w||dz
  k     rt          j        |j                   d{V  g|r|dS )r   NTr   Fr   )	r   rS   rB   r   r   r|   r   rr   r   s	            r    rW   zHealthyAnyPolicy._execute-  s      1x00000000V}} 
	E 
	EG#+886JJJJJJJJ  44   # # #!"# !##mL$CDDDDDDDDD  	!  us   A
A1%A,,A1Nr   r-   r"   r    r   r   (  s@         ; T      r"   r   c                       e Zd ZeZeZeZdS )HealthCheckPoliciesN)	rD   rE   rF   r   HEALTHY_ALLr   HEALTHY_MAJORITYr   HEALTHY_ANYr-   r"   r    r   r   J  s        "K,"KKKr"   r   DEFAULT_HEALTH_CHECK_POLICYc                       e Zd ZeeefdededefdZe	defd            Z
e	defd            Ze	defd            Zed	edefd
            ZdS )AbstractHealthCheckr9   r<   r>   c                 Z    |dk     rt          d          || _        || _        || _        d S )Nr   z*health_check_probes must be greater than 0)r   _health_check_probes_health_check_delay_health_check_timeout)r   r9   r<   r>   s       r    r$   zAbstractHealthCheck.__init__T  s<     ""IJJJ$7!#5 %9"""r"   r   c                     | j         S rb   )r   r8   s    r    r9   z'AbstractHealthCheck.health_check_probes`  s    ((r"   c                     | j         S rb   )r   r8   s    r    r<   z&AbstractHealthCheck.health_check_delayd  s    ''r"   c                     | j         S rb   )r   r8   s    r    r>   z(AbstractHealthCheck.health_check_timeouth  s    ))r"   r?   c                 
   K   d S rb   r-   rA   s      r    rC   z AbstractHealthCheck.check_healthl  s      r"   N)rD   rE   rF   DEFAULT_HEALTH_CHECK_PROBESDEFAULT_HEALTH_CHECK_DELAYDEFAULT_HEALTH_CHECK_TIMEOUTrI   rJ   r$   rH   r9   r<   r>   r   rK   rL   rC   r-   r"   r    r   r   S  s         $?$>&B	
: 
: 
: "
: $	
: 
: 
: 
: )S ) ) ) X) (E ( ( ( X( *e * * * X* 6G D    ^  r"   r   c                   "    e Zd ZdZdedefdZdS )PingHealthCheckz-
    Health check based on PING command.
    r?   r   c                    K   t          |t                    r|                    d           d {V S |                                }|D ]%}|j                            d           d {V s dS &dS )NPINGFT)ro   r}   execute_command	get_nodesredis_connection)r   rB   r?   	all_nodesnodes        r    rC   zPingHealthCheck.check_healthv  s      i,, 		"226::::::::: "++--I! ! !!2BB6JJJJJJJJ ! 55! 4r"   N)rD   rE   rF   rG   rK   rL   rC   r-   r"   r    r   r   q  sA         
6G 
D 
 
 
 
 
 
r"   r   c                        e Zd ZdZdeeddddddddeeefde	de	de
deeeef                  d	ed
ee         dee         deeeef                  dee         dee         dee         de	de
de
f fdZdedefdZ xZS )LagAwareHealthCheckz
    Health check available for Redis Enterprise deployments.
    Verify via REST API that the database is healthy based on different lags.
    i$  NTrest_api_portlag_aware_tolerancehttp_timeout
auth_basic
verify_tlsca_fileca_pathca_dataclient_cert_fileclient_key_fileclient_key_passwordr9   r<   r>   c                     t          t          ||t          t                      d          |||||	|
|
  
                  | _        || _        || _        t                                          |||           dS )a  
        Initialize LagAwareHealthCheck with the specified parameters.

        Args:
            rest_api_port: Port number for Redis Enterprise REST API (default: 9443)
            lag_aware_tolerance: Tolerance in lag between databases in MS (default: 100)
            http_timeout: Request timeout in seconds (default: DEFAULT_TIMEOUT)
            auth_basic: Tuple of (username, password) for basic authentication
            verify_tls: Whether to verify TLS certificates (default: True)
            ca_file: Path to CA certificate file for TLS verification
            ca_path: Path to CA certificates directory for TLS verification
            ca_data: CA certificate data as string or bytes
            client_cert_file: Path to client certificate file for mutual TLS
            client_key_file: Path to client private key file for mutual TLS
            client_key_password: Password for encrypted client private key
        r   )retries)
rf   r   ry   r   r   r   r   r   r   r   )r9   r<   r>   N)	r   r   r   r   _http_client_rest_api_port_lag_aware_tolerancesuperr$   )r   r   r   r   r   r   r   r   r   r   r   r   r9   r<   r>   	__class__s                  r    r$   zLagAwareHealthCheck.__init__  s    H 3$%IKK333%!1 /$7  
 
 ,$7! 31!5 	 	
 	
 	
 	
 	
r"   r?   r   c                   K   |j         t          d          t          |j        t          t
          f          r |j                                        d         }n$|j                                        d         j        }|j          d| j	         }|| j
        j        _        d}| j
                            d           d{V D ]2}|d         D ]'}|d         |k    r|} n|d	         D ]}||k    r|} n(3|)t                              d
           t          d          d|d          d| j         }	| j
                            |	d           d{V  dS )a  
        Check database health via Redis Enterprise REST API.

        Note: The client parameter is not used for this health check as it
        relies on the REST API instead of Redis protocol. The client is
        accepted for interface compatibility.
        Nz[Database health check url is not set. Please check DatabaseConfig for the current database.rt   r   :z/v1/bdbs	endpointsdns_nameaddrz8LagAwareHealthCheck failed: Couldn't find a matching bdbzCould not find a matching bdbz	/v1/bdbs/uidz=/availability?extend_check=lag&availability_lag_tolerance_ms=F)expect_jsonT)health_check_urlr   ro   r|   r}   r~   r   r   rt   r   r   base_urlr{   loggerwarningr   )
r   rB   r?   db_hostr   matching_bdbbdbendpointr   urls
             r    rC   z LagAwareHealthCheck.check_health  s      $,m   ho
I'>?? 	:o;;==fEGG o//11!49G/GG$2EGG,4 ) *..z:::::::: 
	 
	C, 	 	J'722#&LE %V,  Dw'* ' NNUVVV<===[U+ [ [?C?X[ [ 	 ##CU#;;;;;;;;; tr"   )rD   rE   rF   rG   DEFAULT_LAG_AWARE_TOLERANCEr   r   r   r   rI   rJ   r   r   strrL   r
   bytesr$   rK   rC   __classcell__)r   s   @r    r   r     sU         "#>-04!%!%/3*.)--1#>$>&B%8
 8
8
 !8
 	8

 U38_-8
 8
 #8
 #8
 %U
+,8
 #3-8
 "#8
 &c]8
  !!8
" "#8
$ $%8
 8
 8
 8
 8
 8
t/6G /D / / / / / / / /r"   r   )=rg   r   loggingabcr   r   enumr   typingr   r   r   r	   r
   redis.asyncior   r}   redis.asyncio.clusterr   r   redis.asyncio.http.http_clientr   r   redis.backoffr   redis.clientr~   redis.clusterr   redis.http.http_clientr   redis.multidb.exceptionr   redis.retryr   rK   r%   r)   dictr2   r   DEFAULT_HEALTH_CHECK_INTERVALr   r   r   	getLoggerrD   r   r6   rN   r`   r   r   r   r   r   r   __annotations__r   r   r   r-   r"   r    <module>r      s      # # # # # # # #       5 5 5 5 5 5 5 5 5 5 5 5 5 5 - - - - - - C C C C C C R R R R R R R R # # # # # # + + + + + + : : : : : : - - - - - - > > > > > >       *&778 $ 9    =4 =d =t = = = =    !     " 		8	$	$$ $ $ $ $# $ $ $N       <g g g g g 1 g g gT    0   2) ) ) ) )5 ) ) )X    0   D# # # # #$ # # # 4G3R 0 R R R    +   <    )   $o o o o o- o o o o or"   