
    KiW                        U d Z ddlZ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mZmZmZmZ ddlZddl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! erd	dl"m#Z# d	dl$m%Z%  ejL                  e'      Z(ejR                  e*d<   e+e,e,f   Z- G d de.ej^                        Z0ed   Z1 G d dejd                        Z3 G d de3      Z4 G d de3      Z5e6e0ef   Z7e+e.e8e7   f   Z9e+e.e9f   Z: G d d      Z;y)a  Strike list with optional Redis synchronization.

This module provides the StrikeList class which manages strike conditions
for blocking task execution. When connected to Redis, it monitors a stream
for strike/restore instructions issued by external processes.
    N)AsyncExitStackcontextmanager)TracebackType)	TYPE_CHECKINGAnyCallable	GeneratorHashableLiteralMappingNoReturncast)Redis)RedisCluster)Self   )CANCEL_MSG_CLEANUPcancel_task)suppress_instrumentation)	Execution)RedisConnectionloggerc                   (    e Zd ZdZdZdZdZdZdZdZ	y)	Operator==!=>>=<<=betweenN)
__name__
__module____qualname__EQUAL	NOT_EQUALGREATER_THANGREATER_THAN_OR_EQUAL	LESS_THANLESS_THAN_OR_EQUALBETWEEN     ]/home/jay/workspace/scripts/.codegraph-venv/lib/python3.12/site-packages/docket/strikelist.pyr   r   -   s'    EIL IGr-   r   )r   r   r   r   r   r    r!   c            
           e Zd ZU ed   ed<   eed<   dedz  dedz  dededdf
d	Zde	fd
Z
ede	dd fd       Zdeeef   fdZdefdZy)StrikeInstructionstrikerestore	directionoperatorfunctionN	parametervaluereturnc                 <    || _         || _        || _        || _        y N)r6   r7   r5   r8   )selfr6   r7   r5   r8   s        r.   __init__zStrikeInstruction.__init__>   s      !" 
r-   c                 `   d| j                   j                         i}| j                  r| j                  j                         |d<   | j                  r| j                  j                         |d<   | j                  j                         |d<   t        j                  | j                        |d<   |S )N	   direction   function	   parameter   operator   value)r4   encoder6   r7   r5   cloudpickledumpsr8   )r<   messages     r.   
as_messagezStrikeInstruction.as_messageJ   s    '3T^^5J5J5L&M==#'==#7#7#9GK >>$(NN$9$9$;GL!#}}335'--djj9r-   rG   c                 b   t        t        d   |d   j                               }d|v r|d   j                         nd }d|v r|d   j                         nd }t        t        |d   j                               }t	        j
                  |d         }|dk(  rt        ||||      S t        ||||      S )Nr1   r?   r@   rA   rB   rC   r2   )r   r   decoder   rE   loadsStrikeRestore)clsrG   r4   r6   r7   r5   r8   s          r.   from_messagezStrikeInstruction.from_messageT   s    !45w|7L7S7S7UV	4?74J7;'..0PT6Bg6MGL)002SW	'+"6"="="?@!!'("34 (Ix??8Y%@@r-   c                     i }| j                   r| j                   |d<   | j                  r6| j                  |d<   | j                  |d<   t        | j                        |d<   |S )Nzdocket.taskzdocket.parameterzdocket.operatorzdocket.valuer6   r7   r5   reprr8   )r<   labelss     r.   rS   zStrikeInstruction.labels`   sY    !#==$(MMF=!>>)-F%&(,F$%%)$**%5F>"r-   c           	          | j                   xs d d| j                  xs d d| j                   d| j                  rt        | j                         dS d dS )N*( )rQ   r<   s    r.   	call_reprzStrikeInstruction.call_reprl   si    }}#$~~$%}}o#'>>tDJJ;		
 8;;		
r-   )r"   r#   r$   r   __annotations__r   strr
   r=   MessagerH   classmethodrO   r   rS   rZ   r,   r-   r.   r0   r0   :   s    *++
*
 :
 	

 
 

G  	A7 	A/B 	A 	A
S) 


3 

r-   r0   c                   "    e Zd ZU dZed   ed<   y)rL   r2   r1   r4   Nr"   r#   r$   r4   r   r[   r,   r-   r.   rL   rL   y   s    .6Iw*+6r-   rL   c                   "    e Zd ZU dZed   ed<   y)rM   r3   r1   r4   Nr`   r,   r-   r.   rM   rM   }   s    .7Iw*+7r-   rM   c                      e Zd ZU dZeed<   eed<   eedge	f      ed<   e
dz  ed<   ej                  e   dz  ed<   ej                  dz  ed	<   eed
<   	 	 	 d:dedz  dede	ddfdZedefd       Zedefd       Zeded   fd       ZdefdZdee   dz  dedz  dedz  ddfdZdedge	f   ddfdZdedge	f   ddfdZd;dZ de!ddfdZ"	 	 	 	 d<dedz  d edz  d!d"d#e#dz  ddf
d$Z$	 	 	 	 d<dedz  d edz  d!d"d#e#dz  ddf
d%Z%d&d'de	fd(Z&d)e'ee(f   de	fd*Z)d+dde	fd,Z*d#e(d!e+d-e(de	fd.Z,de!ddfd/Z-d0e.ddfd1Z/d2e0ddfd3Z1defd4Z2d5e3e4z  d6ed7e	d8e(de5ee	f   f
d9Z6y)=
StrikeLista)  A strike list that manages conditions for blocking task execution.

    When a URL is provided, the strike list will connect to Redis and monitor
    a stream for strike/restore instructions. External processes (like Docket)
    can issue strikes, and all StrikeList instances listening to the same
    stream will receive and apply those updates.

    Example using context manager with Redis:
        async with StrikeList(url="redis://localhost:6379/0", name="my-docket") as strikes:
            # External process issues: await docket.strike("my_task", "customer_id", "==", "blocked")

            if strikes.is_stricken({"customer_id": "blocked"}):
                print("Customer is blocked")

    Example with Docket (managed internally):
        async with Docket(name="my-docket", url="redis://localhost:6379/0") as docket:
            # Docket manages its own StrikeList internally
            await docket.strike(None, "customer_id", "==", "blocked")

    Example using explicit connect/close:
        strikes = StrikeList(url="redis://localhost:6379/0", name="my-docket")
        await strikes.connect()
        try:
            if strikes.is_stricken({"customer_id": "blocked"}):
                print("Customer is blocked")
        finally:
            await strikes.close()

    Example without Redis (local-only):
        strikes = StrikeList()  # No URL = no Redis connection
        strikes.update(Strike(None, "customer_id", Operator.EQUAL, "blocked"))
        if strikes.is_stricken({"customer_id": "blocked"}):
            print("Customer is blocked")
    task_strikesparameter_strikesr   _conditionsN_redis_monitor_task_strikes_loaded_stackurlnameenable_internal_instrumentationr9   c                     || _         || _        || _        i | _        i | _        | j
                  g| _        |rt        |      nd| _        d| _	        d| _
        y)a  Initialize a StrikeList.

        Args:
            url: Redis connection URL. Use "memory://" for in-memory testing.
                 If None, no Redis connection is made (local-only mode).
            name: Name used as prefix for Redis keys (should match the Docket name
                  if you want to receive strikes from that Docket).
            enable_internal_instrumentation: If True, allows OpenTelemetry spans
                for internal Redis operations. Default False suppresses these spans.
        N)rk   rl   rm   rd   re   !_matches_task_or_parameter_strikerf   r   rg   rh   ri   )r<   rk   rl   rm   s       r.   r=   zStrikeList.__init__   s[      	/N,!# BBC.1oc*t!#r-   c                 |    | j                   %| j                   j                  | j                        S | j                  S )zReturn the key prefix for this strike list.

        All Redis keys for this strike list are prefixed with this value.

        For Redis Cluster mode, returns a hash-tagged prefix like "{myapp}"
        to ensure all keys hash to the same slot.
        )rg   prefixrl   rY   s    r.   rq   zStrikeList.prefix   s1     ;;";;%%dii00yyr-   c                      | j                    dS )z)Redis stream key for strike instructions.z:strikes)rq   rY   s    r.   
strike_keyzStrikeList.strike_key   s     ++h''r-   )NNNc              #   t   K   | j                   st               5  d ddd       yd y# 1 sw Y   yxY ww)zASuppress OTel auto-instrumentation for internal Redis operations.N)rm   r   rY   s    r.   _maybe_suppress_instrumentationz*StrikeList._maybe_suppress_instrumentation   s8      33)+    s   8,858c                    K   t                _         j                  j                          d{     j                   S  j                  j                  rJ d        j                  j                   j                         d{    t        j                          _         j                  j                   fd       t        j                   j                          j                   d       _         j                  j                   fd        j                  j                  t         j                  t                 S 7 7 ĭw)z@Async context manager entry - connects to Redis if URL provided.NzStrikeList is not reentrantc                      t         dd       S )Nri   setattrrY   s   r.   <lambda>z'StrikeList.__aenter__.<locals>.<lambda>   s    WT3Dd%K r-   z - strike monitor)rl   c                      t         dd       S )Nrh   rx   rY   s   r.   rz   z'StrikeList.__aenter__.<locals>.<lambda>   s    WT?D%I r-   )r   rj   
__aenter__rg   is_connectedenter_async_contextasyncioEventri   callbackcreate_task_monitor_strikesrl   rh   push_async_callbackr   r   rY   s   `r.   r|   zStrikeList.__aenter__   s     $&kk$$&&&;;K;;++J-JJ+kk--dkk:::&}}KL$00!!#TYYK7H*I
 	IJ''++-?	
 ' 	' 	;s#   -EE
AEE	CEEexc_type	exc_value	tracebackc                 n   K   	 | j                   j                  |||       d{    | ` y7 # | ` w xY ww)z5Async context manager exit - closes Redis connection.N)rj   	__aexit__)r<   r   r   r   s       r.   r   zStrikeList.__aexit__   s8     	++'')YGGG Hs    5 . ,. 5. 25	conditionc                 <    | j                   j                  d|       y)zCAdds a temporary condition that indicates an execution is stricken.r   N)rf   insertr<   r   s     r.   add_conditionzStrikeList.add_condition  s    9-r-   c                 Z    || j                   usJ | j                  j                  |       y)zFRemoves a temporary condition that indicates an execution is stricken.N)ro   rf   remover   s     r.   remove_conditionzStrikeList.remove_condition  s*     F FFFF	*r-   c                 n   K   | j                   y| j                   j                          d{    y7 w)al  Wait for all existing strikes to be loaded from the stream.

        This method blocks until the strike monitor has completed its initial
        non-blocking read of all existing strike messages. Call this before
        making decisions that depend on the current strike state.

        If not connected to Redis (local-only mode), returns immediately.
        N)ri   waitrY   s    r.   wait_for_strikes_loadedz"StrikeList.wait_for_strikes_loaded  s/      '""'')))s   +535instructionc                   K   | j                   | j                   j                  st        d      | j                   j                         4 d{   }|j	                  | j
                  |j                                d{    ddd      d{    | j                  |       y7 X7 (7 # 1 d{  7  sw Y   *xY ww)zSend a strike instruction to Redis and update local state.

        Args:
            instruction: The Strike or Restore instruction to send.

        Raises:
            RuntimeError: If not connected to Redis.
        NzeCannot send strike instruction: not connected to Redis. Use connect() or async context manager first.)rg   r}   RuntimeErrorclientxaddrs   rH   update)r<   r   rs      r.   send_instructionzStrikeList.send_instruction!  s      ;;dkk&>&>@ 
 ;;%%' 	D 	D1&&+*@*@*BCCC	D 	D 	K 	DC	D 	D 	D 	DsZ   ACB'C.B- B)B-CB+C)B-+C-B?3B64B?;Cr6   r7   r5   zOperator | LiteralOperatorr8   c                 p   K   t        ||t        |      |      }| j                  |       d{    y7 w)aG  Issue a strike to block matching tasks or parameters.

        Args:
            function: Task function name to strike, or None for all tasks.
            parameter: Parameter name to match, or None for entire task.
            operator: Comparison operator for the value.
            value: Value to compare against.
        N)rL   r   r   r<   r6   r7   r5   r8   r   s         r.   r2   zStrikeList.strike5  s1      Xy(82DeL##K000   ,646c                 p   K   t        ||t        |      |      }| j                  |       d{    y7 w)a6  Restore a previously issued strike.

        Args:
            function: Task function name to restore, or None for all tasks.
            parameter: Parameter name to match, or None for entire task.
            operator: Comparison operator for the value.
            value: Value to compare against.
        N)rM   r   r   r   s         r.   r3   zStrikeList.restoreG  s1      h	8H3EuM##K000r   targetzExecution | Mapping[str, Any]c                     t        t              r| j                        S t        fd| j                  D              S )a4  Check if a target matches any strike condition.

        Args:
            target: Either an Execution object (for Docket/Worker use) or
                   a dictionary of parameter names to values (for standalone use).

        Returns:
            True if any parameter matches a strike condition.
        c              3   .   K   | ]  } |        y wr;   r,   ).0r   r   s     r.   	<genexpr>z)StrikeList.is_stricken.<locals>.<genexpr>h  s     G9V$Gs   )
isinstancer   _is_dict_strickenanyrf   )r<   r   s    `r.   is_strickenzStrikeList.is_strickenY  s9     fg&))&11 Gd6F6FGGGr-   paramsc                     |j                         D ]A  \  }}|| j                  vr| j                  |   D ]  \  }}| j                  |||      s  y C y)zCheck if a parameter dict matches any strike condition.

        Args:
            params: Dictionary of parameter names to values.

        Returns:
            True if any parameter matches a strike condition.
        TF)itemsre   	_is_match)r<   r   r7   argumentr5   strike_values         r.   r   zStrikeList._is_dict_strickenj  sf     $*<<> 	 Ix 6 66*.*@*@*K  &,>>(HlC 		  r-   	executionc                 z   ddl m} |j                  }| j                  j	                  |i       }|| j                  v r|sy ||j
                        }	  |j                  |j                  i |j                  }|j                          i |j                  |j                  j                         D ci c]  \  }}||j                  vr|| c}}}	|	j                         D ]A  \  }
}|| j                  fD ]+  }|
|vr||
   D ]  \  }}| j                  |||      s   y - C y# t        $ r Y yw xY wc c}}w )Nr   )get_signatureTF)r   r   function_namerd   getr6   bindargskwargsapply_defaults	TypeError	argumentsr   re   r   )r<   r   r   r   rd   	signature
bound_argskvall_argumentsr7   r   strike_sourcer5   r   s                  r.   ro   z,StrikeList._matches_task_or_parameter_strike}  sa   ,!// ((,,]B?D---l!)"4"45		'L9;K;KLJ%%'

""
 &,,224AqJ000 1
 $1#6#6#8 	$Ix".0F0F!G $M1.;I.F $*Hl~~h,G#$	$	$ -  		s   6D( 3D7(	D43D4r   c                 8   	 |xdk(  r ||k(  S xdk(  r ||k7  S xdk(  r ||kD  S xdk(  r ||k\  S xdk(  r ||k  S xdk(  r ||k  S dk(  r|\  }}||cxk  xr |k  S c S 	 t        d|       # t         t        f$ r t        j                  d	|||d
       Y yw xY w)z1Determines if a value matches a strike condition.r   r   r   r   r   r    r!   zUnknown operator: z0Incompatible type for strike condition: %r %s %rT)exc_infoF)
ValueErrorr   r   warning)r<   r8   r5   r   loweruppers         r.   r   zStrikeList._is_match  s    	 L00 L00 <// L00 <// L00#/LE5 E2U2222$'9(%DEEI& 
	 NNB   
	s<   A- 
A- 
A- 
A- 
A- 
A- A- A- A- -)BBc                 ,   	 t        |j                         t        |t              r| j                  |       y t        |t              r| j                  |       y y # t        $ r. t        j	                  d|j
                  |j                         Y y w xY w)Nz-Incompatible type for strike condition: %s %r)hashr8   r   r   r   r5   r   rL   _strikerM   _restore)r<   r   s     r.   r   zStrikeList.update  s    	""# k6*LL%W-MM+& .  	NN?$$!!
 	s   A 4BBr2   c                    |j                   r^|j                  rR	 | j                  |j                      }	 ||j                     }|j                  |j                  |j                  f       y |j                   r	 | j                  |j                      }y |j                  rB	 | j                  |j                     }|j                  |j                  |j                  f       y y # t        $ r i x}| j                  |j                   <   Y w xY w# t        $ r t	               x}||j                  <   Y w xY w# t        $ r i x}| j                  |j                   <   Y y w xY w# t        $ r& t	               x}| j                  |j                  <   Y w xY wr;   )	r6   r7   rd   KeyErrorsetaddr5   r8   re   )r<   r2   rd   re   s       r.   r   zStrikeList._strike  s{   ??v//G#00AK$01A1A$B! !!6??FLL"AB__G#00A U$($:$:6;K;K$L! !!6??FLL"AB !  GDFFt00AG
  KEHUJ!L1A1A$BK  GDFFt00AG  UORuT!D$:$:6;K;K$LUsF   C! D 8D3 E !$DD"D0/D03$EE,FFr3   c                    |j                   r|j                  r	 | j                  |j                      }	 ||j                     }	 |j                  |j                  |j                  f       |sF|j	                  |j                  d        |s'| j                  j	                  |j                   d        y y y |j                   rD	 | j                  |j                      }|s'| j                  j	                  |j                   d        y y |j                  rl	 | j                  |j                     }	 |j                  |j                  |j                  f       |s'| j                  j	                  |j                  d        y y y # t        $ r Y y w xY w# t        $ r |j	                  |j                  d        Y y w xY w# t        $ r Y Xw xY w# t        $ r Y y w xY w# t        $ r Y y w xY w# t        $ r Y w xY wr;   )	r6   r7   rd   r   popr   r5   r8   re   )r<   r3   rd   re   s       r.   r   zStrikeList._restore  s    1 1#001A1AB$01B1B$C!
!(('*:*:GMM)JK %  !2!2D9#%%))'*:*:DA $ %
 #001A1AB
  !!%%g&6&6=   $($:$:7;L;L$M!!(('*:*:GMM)JK %&&**7+<+<dC % ;  
    !2!2D9      
  sj   E= F 'F7 G G +'G% =	F	F	%F43F47	GG	GG	G"!G"%	G10G1c                 d  K   ddl m}m} | j                  J d}d}	 	 | j                  j	                         4 d{   }	 | j                  ||||       d{   \  }} 7 %7 
# 1 d{  7  sw Y   nxY wn# t        j                  j                  $ rT |j                  dd| j                  i       t        j                  d       t        j                  d       d{  7   Y nAt        $ r6 t        j!                  d       t        j                  d       d{  7   Y nw xY ww)	z7Background task that monitors Redis for strike updates.r   )REDIS_DISRUPTIONSSTRIKES_IN_EFFECTNz0-0Fdocketz*Connection error, sleeping for 1 second...zError monitoring strikes)instrumentationr   r   rg   r   _read_strikesredis
exceptionsConnectionErrorr   rl   r   r   r   sleep	Exception	exception)r<   r   r   last_idinitial_load_completer   s         r.   r   zStrikeList._monitor_strikes   s    I{{&&& %';;--/  1?C?Q?Qw(=?P@ :6!6 :   
 ##33 '!%%a(DII)>?KLmmA&&& '  !;<mmA&&&' s   D0A= A#A= A'A%A'#A= %A''A9-A0.A95A= <D0=A(D+%C(&D++D0-5D+"D%#D+(D0*D++D0r   r   r   strikes_in_effectc                   K   | j                         5  |j                  | j                  |id|rdnd       d{   }ddd       s0|s.d}| j                  J | j                  j	                          ||fS |sJ|rH| j
                  r8| j
                  j                  d      rt        j                  d       d{    ||fS |D ]  \  }}|D ]  \  }}	|}t        j                  |	      }
| j                  |
       t        j                  d|
j                  d	k(  rd
nd|
j                                |j!                  |
j                  d	k(  rdndd| j"                  i|
j%                                  ||fS 7 @# 1 sw Y   @xY w7 ͭw)zRead and process strike messages from Redis stream.

        Returns:
            Tuple of (last_id, initial_load_complete) to allow state persistence.
        d   i`  N)countblockTz	memory://g?z%s %rr2   Striking	Restoringr   zdocket.name)ru   xreadrs   ri   r   rk   
startswithr   r   r0   rO   r   r   infor4   rZ   r   rl   rS   )r<   r   r   r   r   streams_messages
message_idrG   r   s              r.   r   zStrikeList._read_strikes7  s     113 	 GG'* 5f4 $  G		 4$(!''333  $$&1110xxDHH//<mmC(((111" 	KAx'/ #
G$/<<WEK(#.#8#8H#DZ+))+ "%%$..(:A%tyy%,,.	& ---M		 	( )s:   F(E>E;E> A=F=F>B=F;E>>F	F)N
strikelistF)r9   N)NNr   N)7r"   r#   r$   __doc__TaskStrikesr[   ParameterStrikeslistr   boolr   r   Taskr   r   r   r\   r=   propertyrq   rs   r   r	   ru   r   r|   typeBaseExceptionr   r   r   r   r   r0   r   r
   r2   r3   r   r   r   r   ro   r   r   r   rL   r   rM   r   r   r   r   tupler   r,   r-   r.   rc   rc      s+   !F ''h}d2344d""<<)D00]]T))  05	$4Z$ $ *.	$
 
$4 
 
 
 (C ( ( ;K1L  $ 0
}%,
 !4'
 !4'	

 

.xt0C'D . .+(K=$3F*G +D +
*!2C ! !,  $ $15!%1*1 :1 /	1
 $1 
1(  $ $15!%1*1 :1 /	1
 $1 
1$H"A Hd H"S(9 d &%; %4 %Ns h c d B'"3 ' ' Cf C C8-D -DD -D^' '.6.<6. 6.  $	6.
 6. 
sDy	6.r-   rc   )<r   abcr   enumlogging
contextlibr   r   typesr   typingr   r   r   r	   r
   r   r   r   r   rE   redis.exceptionsr   redis.asyncior   redis.asyncio.clusterr   typing_extensionsr   _cancellationr   r   
_telemetryr   r   r   rg   r   	getLoggerr"   r   Loggerr[   dictbytesr]   r\   Enumr   LiteralOperatorABCr0   rL   rM   r   MinimalStriker   r   r   rc   r,   r-   r.   <module>r     s       5 
 
 
    . " : 0$ #***84 4
ue|
sDII  EF<
 <
~7 78 8 h()S//0 3(()g. g.r-   