
     ih                         S r SSKrSSKrSSKrSSKrSSKrSSKrSSKrSSKJ	r	  SSK
JrJr  SSKJrJrJrJr  SSKJrJrJrJrJrJrJrJrJrJrJrJrJrJ r J!r!  SSK"J#r#   " S	 S
5      r$g)z
Dirty Arbiter Process

Asyncio-based arbiter that manages the dirty worker pool and routes
requests from HTTP workers to available dirty workers.
    N)util   )get_app_workers_attributeparse_dirty_app_spec)
DirtyErrorDirtyNoWorkersAvailableErrorDirtyTimeoutErrorDirtyWorkerError)DirtyProtocolmake_error_responsemake_responseSTASH_OP_PUTSTASH_OP_GETSTASH_OP_DELETESTASH_OP_KEYSSTASH_OP_CLEARSTASH_OP_INFOSTASH_OP_ENSURESTASH_OP_DELETE_TABLESTASH_OP_TABLESSTASH_OP_EXISTSMANAGE_OP_ADDMANAGE_OP_REMOVE)DirtyWorkerc                   l   \ rS rSrSrSR                  5        V VVVs/ s H  n[        [        SU-  5      PM     snnnn rSr	S(S jr
S rS	 rS
 rS rS rS rS rS rS rS rS rS rS rS rS rS rS)S jrS rS rS rS rS r S r!S*S jr"S  r#S! r$S" r%S# r&S$ r'S+S% jr(S& r)S'r*gs  snnnn f ),DirtyArbiter1   a  
Dirty arbiter that manages the dirty worker pool.

The arbiter runs an asyncio event loop and handles:
- Spawning and managing dirty worker processes
- Accepting connections from HTTP workers
- Routing requests to available dirty workers
- Monitoring worker health via heartbeat
z*HUP QUIT INT TERM TTIN TTOU USR1 USR2 CHLDzSIG%s   Nc                 P   Xl         X l        SU l        [        R                  " 5       U l        X@l        [        R                  " SS9U l	        U=(       d*    [        R                  R                  U R                  S5      U l        0 U l        0 U l        0 U l        0 U l        0 U l        SU l        SU l        SU l        U R                   R*                  U l        SU l        SU l        0 U l        0 U l        0 U l        0 U l        0 U l        / U l        0 U l        U RA                  5         g)z
Initialize the dirty arbiter.

Args:
    cfg: Gunicorn config
    log: Logger
    socket_path: Path to the arbiter's Unix socket
    pidfile: Well-known PID file location for orphan detection
Nzgunicorn-dirty-)prefixzarbiter.sockr   T)!cfglogpidosgetpidppidpidfiletempfilemkdtemptmpdirpathjoinsocket_pathworkersworker_socketsworker_connectionsworker_queuesworker_consumers_worker_rr_index
worker_agealivedirty_workersnum_workers_server_loop_pending_requests	app_specsapp_worker_mapworker_app_map_app_rr_indices_pending_respawnsstash_tables_parse_app_specs)selfr!   r"   r-   r'   s        H/var/www/ias/venv/lib/python3.13/site-packages/gunicorn/dirty/arbiter.py__init__DirtyArbiter.__init__B   s	    IIK	 &&.?@& 
"'',,KK+
  "$ " !
8811
!#   !!#  	    c                 0   U R                   R                   HI  n[        U5      u  p#Uc   [        U5      nUUUS.U R                  U'   [        5       U R                  U'   MK     g! [         a&  nU R
                  R                  SX$5         SnANZSnAff = f)aK  
Parse all app specifications from config.

Populates self.app_specs with parsed information about each app,
including the import path and worker count limits.

Worker count priority:
1. Config override (e.g., "module:Class:2") - highest priority
2. Class attribute (e.g., workers = 2 on the class)
3. None (all workers) - default
Nz,Could not read workers attribute from %s: %s)import_pathworker_countoriginal_spec)
r!   
dirty_appsr   r   	Exceptionr"   warningr;   setr<   )rB   specrH   rI   es        rC   rA   DirtyArbiter._parse_app_specsy   s     HH''D(<T(B%K ##<[#IL  + ,!%+DNN;' 03uD,) ( ! HH$$F# s   A%%
B/BBc                 v    SnU R                   R                  5        H  nUS   nUc  M  [        X5      nM     U$ )z
Calculate minimum number of workers required by app specs.

Returns the maximum worker_count across all apps that have limits.
Apps with worker_count=None don't impose a minimum.

Returns:
    int: Minimum workers required (at least 1)
r   rI   )r;   valuesmax)rB   min_requiredrO   rI   s       rC   _get_minimum_workers!DirtyArbiter._get_minimum_workers   sB     NN))+D/L'"<> , rF   c                    / nU R                   R                  5        He  u  p#US   n[        U R                  R	                  U[        5       5      5      nUc  UR                  U5        MM  XT:  d  MT  UR                  U5        Mg     U$ )aP  
Determine which apps a new worker should load.

Returns a list of import paths for apps that need more workers.
Apps with workers=None (all workers) are always included.
Apps with worker limits are included only if they haven't
reached their limit yet.

Returns:
    List of import paths to load, or empty list if no apps need workers
rI   )r;   itemslenr<   getrN   append)rB   	app_pathsrH   rO   rI   current_workerss         rC   _get_apps_for_new_worker%DirtyArbiter._get_apps_for_new_worker   s~     	!%!5!5!7K/L!$"5"5"9"9+su"MNO #  - /  - "8 rF   c                     [        U5      U R                  U'   U HG  nX0R                  ;  a  [        5       U R                  U'   U R                  U   R	                  U5        MI     g)a  
Register which apps a worker has loaded.

Updates both app_worker_map and worker_app_map to track the
bidirectional relationship between workers and apps.

Args:
    worker_pid: The PID of the worker
    app_paths: List of app import paths loaded by this worker
N)listr=   r<   rN   addrB   
worker_pidr]   app_paths       rC   _register_worker_apps"DirtyArbiter._register_worker_apps   sY     +/y/J'!H22203##H-)--j9 "rF   c                     U R                   R                  U/ 5      nU H2  nX0R                  ;   d  M  U R                  U   R                  U5        M4     g)z
Unregister a worker's apps when it exits.

Removes the worker from all tracking maps.

Args:
    worker_pid: The PID of the worker to unregister
N)r=   popr<   discardrd   s       rC   _unregister_workerDirtyArbiter._unregister_worker   sM     ''++J;	 "H...##H-55jA "rF   c                 &   [         R                  " 5       U l        U R                  R	                  SU R                  5        U R
                  (       aD   [        U R
                  S5       nUR                  [        U R                  5      5        SSS5        U R                  [         R                  S'   U R                  R                  U 5        U R                  5         [         R"                  " S5         [$        R&                  " U R)                  5       5        U R-                  5         g! , (       d  f       N= f! [         a&  nU R                  R                  SU5         SnANSnAff = f! [*         a     Naf = f! U R-                  5         f = f)z&Run the dirty arbiter (blocking call).z Dirty arbiter starting (pid: %s)wNzFailed to write PID file: %sGUNICORN_DIRTY_SOCKETzdirty-arbiter)r$   r%   r#   r"   infor'   openwritestrIOErrorrM   r-   environr!   on_dirty_startinginit_signalsr   _setproctitleasynciorun
_run_asyncKeyboardInterrupt_cleanup_sync)rB   frP   s      rC   r{   DirtyArbiter.run   s!   99;8$((C <<D$,,,GGCM* - /3.>.>

*+ 	""4( 	 	?+	!KK)*  - -, D  !?CCD" ! 		  sZ   D; )%D*D; 5$E. *
D84D; 8D; ;
E+E&&E+.
E;8E> :E;;E> >Fc                 d   U R                    H(  n[        R                  " U[        R                  5        M*     [        R                  " [        R                  U R                  5        [        R                  " [        R
                  U R                  5        [        R                  " [        R                  U R                  5        [        R                  " [        R                  U R                  5        [        R                  " [        R                  U R                  5        [        R                  " [        R                  U R                  5        [        R                  " [        R                  U R                  5        [        R                  " [        R                  U R                  5        g)zSet up signal handlers.N)SIGNALSsignalSIG_DFLSIGTERM_signal_handlerSIGQUITSIGINTSIGHUPSIGUSR1SIGCHLDSIGTTINSIGTTOU)rB   sigs     rC   rx   DirtyArbiter.init_signals
  s    <<CMM#v~~.   	fnnd&:&:;fnnd&:&:;fmmT%9%9:fmmT%9%9:fnnd&:&:;fnnd&:&:;fnnd&:&:;fnnd&:&:;rF   c                 n  ^  U[         R                  :X  a1  T R                  (       a  T R                  R                  U 4S j5        gU[         R                  :X  a  T R
                  R                  5         gU[         R                  :X  a1  T R                  (       a  T R                  R                  U 4S j5        gU[         R                  :X  al  T =R                  S-  sl	        T R
                  R                  ST R                  5        T R                  (       a  T R                  R                  U 4S j5        gU[         R                  :X  a  T R                  5       nT R                  U::  a  T R
                  R                  SU5        gT =R                  S-  sl	        T R
                  R                  ST R                  5        T R                  (       a  T R                  R                  U 4S	 j5        gS
T l        T R                  (       a&  T R                  R                  T R                  5        gg)zHandle signals.c                  L   > [         R                  " T R                  5       5      $ N)rz   create_task_handle_sigchldrB   s   rC   <lambda>.DirtyArbiter._signal_handler.<locals>.<lambda>  s    G//0D0D0FGrF   Nc                  L   > [         R                  " T R                  5       5      $ r   )rz   r   reloadr   s   rC   r   r   +  s    G//>rF   r   z'SIGTTIN: Increasing dirty workers to %sc                  L   > [         R                  " T R                  5       5      $ r   rz   r   manage_workersr   s   rC   r   r   6      G//0C0C0EFrF   zASIGTTOU: Cannot decrease below %s workers (required by app specs)z'SIGTTOU: Decreasing dirty workers to %sc                  L   > [         R                  " T R                  5       5      $ r   r   r   s   rC   r   r   I  r   rF   F)r   r   r9   call_soon_threadsafer   r"   reopen_filesr   r   r7   rq   r   rV   rM   r5   	_shutdown)rB   r   framemin_workerss   `   rC   r   DirtyArbiter._signal_handler  s   &.. zz

//G &.. HH!!#&--zz

//> &.. !HHMMC**,zz

//F &.. 335K;.  .
 !HHMMC**,zz

//F  
::JJ++DNN; rF   c                 \    U R                   (       a  U R                   R                  5         gg)zInitiate async shutdown.N)r8   closer   s    rC   r   DirtyArbiter._shutdownR  s    <<LL  rF   c                   #    [         R                  " 5       U l        [        R                  R                  U R                  5      (       a   [        R                  " U R                  5        [         R                  " U R                  U R                  S9I Sh  vN U l
        [        R                  " U R                  S5        U R                  R                  SU R                  5        U R                  5       I Sh  vN   [         R                  " U R!                  5       5      n U R                   ISh  vN   U R                  R#                  5       I Sh  vN   SSS5      ISh  vN   UR)                  5          UI Sh  vN   U R+                  5       I Sh  vN   g GN	 N No NO NA! , ISh  vN  (       d  f       NV= f! [         R$                  [&        4 a     Nuf = f Nb! [         R$                   a     Nvf = f Nf! UR)                  5          UI Sh  vN    O! [         R$                   a     Of = fU R+                  5       I Sh  vN    f = f7f)z/Main async loop - start server, manage workers.)r+   Ni  zDirty arbiter listening on %s)rz   get_running_loopr9   r$   r+   existsr-   unlinkstart_unix_serverhandle_clientr8   chmodr"   rq   r   r   _worker_monitorserve_foreverCancelledErrorRuntimeErrorcancelstop)rB   monitor_tasks     rC   r|   DirtyArbiter._run_asyncW  s    --/
 77>>$**++IId&&' %66!!
 
 	!!5)5t7G7GH !!### **4+?+?+AB	|||ll00222 $| !""" ))+;
 	$ $2 $|||&&5 		 #))   !"""))  ))+s9  BIF A#I;F#<(I%G 5F%6G 9F+F'F+G 'F)(G ,I=G' G%G' IHI#I%G 'F+)G +G1F42G>G H G G"H !G""H %G' 'G>;I=G>>IIH!HH! I!H85I7H88IIIIc                   #    U R                   (       a  [        R                  " S5      I Sh  vN   [        R                  " 5       U R
                  :w  a3  U R                  R                  S5        SU l         U R                  5         gU R                  5       I Sh  vN   U R                  5       I Sh  vN   U R                   (       a  M  gg N N3 N7f)z1Periodically check worker health and manage pool.g      ?Nz+Parent changed, shutting down dirty arbiterF)r5   rz   sleepr$   getppidr&   r"   rM   r   murder_workersr   r   s    rC   r   DirtyArbiter._worker_monitor  s     jj--$$$ zz|tyy(  !NO"
 %%'''%%''' jjj$ ('s:   +CCA-CCC3C4CCCCc                    #    U R                  5         U R                  (       a  U R                  5       I Sh  vN   gg N7f)z#Handle SIGCHLD - reap dead workers.N)reap_workersr5   r   r   s    rC   r   DirtyArbiter._handle_sigchld  s2     ::%%''' 's   5A >A c                   #    U R                   R                  S5         U R                  (       a   [        R                  " U5      I Sh  vN nUR                  S5      nU[        R                  :X  a  U R                  X25      I Sh  vN   OuU[        R                  :X  a  U R                  X25      I Sh  vN   OGU[        R                  :X  a  U R                  X25      I Sh  vN   OU R                  X25      I Sh  vN   U R                  (       a  M  UR#                  5          UR%                  5       I Sh  vN   g N! [
        R                   a     MC  f = f N N N| Nd! [         a&  nU R                   R!                  SU5         SnANzSnAff = f N]! [         a     gf = f! UR#                  5          UR%                  5       I Sh  vN    f ! [         a     f f = f= f7f)z
Handle a connection from an HTTP worker.

Routes requests to available dirty workers and returns responses.
Supports both regular responses and streaming (chunk-based) responses.
Also handles stash (shared state) operations.
z&New client connection from HTTP workerNtypezClient connection error: %s)r"   debugr5   r   read_message_asyncrz   IncompleteReadErrorr[   MSG_TYPE_STASHhandle_stash_requestMSG_TYPE_STATUShandle_status_requestMSG_TYPE_MANAGEhandle_manage_requestroute_requestrL   errorr   wait_closed)rB   readerwritermessagemsg_typerP   s         rC   r   DirtyArbiter.handle_client  s     	?@	**$1$D$DV$LLG #;;v. };;;33GDDD!>!>>44WEEE!>!>>44WEEE ,,W===' ***. LLN((***/ M22  E F F > 	=HHNN8!<<	=
 +  LLN((*** s  G)E% E 
E E 9E% E	-E% 6E7-E% $E!%E% >E#?E% G)'F :F;F ?G) E EE% F* EE% E% !E% #E% %
F/FF* FF* F 
F'$G)&F''G)*G&<GGGG&
G# G&"G##G&&G)c           	      $  #    UR                  SS5      nUR                  S5      nU R                  U5      I Sh  vN nUcv  U R                  (       d  [        S5      nO/U(       a  U R                  (       a  [        U5      nO[        S5      n[        X65      n[        R                  " X'5      I Sh  vN   gXPR                  ;  a  U R                  U5      I Sh  vN   U R                  U   n[        R                  " 5       R                  5       n	UR                  XU	45      I Sh  vN    U	I Sh  vN   g N N Na N N! [         a@  n
[        U[!        SU
 3US95      n[        R                  " X'5      I Sh  vN     Sn
A
gSn
A
ff = f7f)a  
Route a request to an available dirty worker via queue.

Each worker has a dedicated queue and consumer task. Requests are
submitted to the queue and processed sequentially by the consumer.

For streaming responses, messages (chunks) are forwarded directly
to the client_writer as they arrive from the worker.

Args:
    request: Request message dict
    client_writer: StreamWriter to send responses to client
idunknownrf   NzNo dirty workers availablezRequest failed: 	worker_id)r[   _get_available_workerr.   r   r;   r   r   r   write_message_asyncr1   _start_worker_consumerrz   r   create_futureputrL   r
   )rB   requestclient_writer
request_idrf   re   r   responsequeuefuturerP   s              rC   r   DirtyArbiter.route_request  sa     [[y1
;;z*  55h??
<<"#?@dnn4X>"#?@*:=H33MLLL ///--j999"":.))+99; ii8999	MLL5 @ M
 : 	:  	M* #3A3!7:NH  33MLLL	Ms   8FD9A7F2D;3(FD=AF(D?)F.E 3E4E 8F;F=F?FE 
F0F=F >FFFFc                    ^ ^^#    [         R                  " 5       mTT R                  T'   UU U4S jn[         R                  " U" 5       5      nUT R                  T'   g7f)z3Start a consumer task for a worker's request queue.c                    >#    TR                   (       a   TR                  5       I S h  vN u  pn TR                  TX5      I S h  vN   UR                  5       (       d  UR	                  S 5        TR                  5         TR                   (       a  M  g g  Nm NQ! [
         a0  nUR                  5       (       d  UR                  U5         S nAN^S nAff = f! TR                  5         f = f! [        R                   a     g f = f7fr   )
r5   r[   _execute_on_workerdone
set_resultrL   set_exception	task_donerz   r   )r   r   r   rP   r   rB   re   s       rC   consumer5DirtyArbiter._start_worker_consumer.<locals>.consumer  s     **;@99;5F2GF
*"55&    &{{}}"--d3
 ) ***5F
 % 4%{{}}"0034 )-- s   DC- BC- B B*B 2C- DDC- B 
C%&CC CC C**C- -DDDDN)rz   Queuer1   r   r2   )rB   re   r   taskr   s   ``  @rC   r   #DirtyArbiter._start_worker_consumer  sJ     ).:&	$ ""8:.,0j)s   AAc           	        #    UR                  SS5      n U R                  U5      I Sh  vN u  pV[        R                  " Xb5      I Sh  vN     [        R
                  " [        R                  " U5      U R                  R                  S9I Sh  vN nUR                  S5      n	U	[        R                  :X  a   [        R                  " X75      I Sh  vN   M  U	[        R                  :X  a  [        R                  " X75      I Sh  vN   gU	[        R                  [        R                  4;   a  [        R                  " X75      I Sh  vN   gU R                   R#                  SU	5        GM    GNF GN) N! [        R                   aL    [        U[        SU R                  R                  5      5      n[        R                  " X85      I Sh  vN     gf = f GN N N! [$         am  n
U R                   R'                  SX5        U R)                  U5        [        U[+        S	U
 3US
95      n[        R                  " X85      I Sh  vN     Sn
A
gSn
A
ff = f7f)z
Execute request on a specific worker (called by consumer).

Handles both regular responses and streaming (chunk-based) responses.
For streaming, chunk and end messages are forwarded directly to the
client_writer as they arrive from the worker.
r   r   N)timeoutzWorker timeoutr   z$Unknown message type from worker: %sz Error executing on worker %s: %szWorker communication failed: r   )r[   _get_worker_connectionr   r   rz   wait_forr   r!   dirty_timeoutTimeoutErrorr   r	   MSG_TYPE_CHUNKMSG_TYPE_ENDMSG_TYPE_RESPONSEMSG_TYPE_ERRORr"   rM   rL   r   _close_worker_connectionr
   )rB   re   r   r   r   r   r   r   r   r   rP   s              rC   r   DirtyArbiter._execute_on_worker  s     [[y1
0	M#'#>#>z#JJNF33FDDD $+$4$4%88@ $ 6 6% G #;;v. };;;';;MSSS }999';;MSSS  ? ? - < < > >';;MSSS   !GRC 	 KD
 ++ 2")*:DHH<R<RS H (;;MTTT T
 T T  	MHHNN=zM))*5* #@!D+57H
  33MLLL	Ms   IG" E0G" 
E3G" A E8 E6E8 >G" G3G" G	G" I=G" G G" I G" 3G" 6E8 8AGGGG" IGG" G"  G" "
I,AI	I
IIIIc                   #    U(       a:  U R                   (       a)  XR                  ;   a  [        U R                  U   5      nO$g[        U R                  R	                  5       5      nU(       d  gU(       aL  U R                   (       a;  U R
                  R                  US5      nUS-   [        U5      -  U R
                  U'   O"U R                  nUS-   [        U5      -  U l        X#[        U5      -     $ 7f)a  
Get an available worker PID using round-robin selection.

If app_path is provided, only returns workers that have loaded
that specific app. Uses per-app round-robin to ensure fair
distribution among eligible workers.

Args:
    app_path: Optional import path of the target app. If None,
             returns any worker using global round-robin.

Returns:
    Worker PID or None if no eligible workers are available.
Nr   r   )	r;   r<   rb   r.   keysr>   r[   rZ   r3   )rB   rf   eligible_pidsidxs       rC   r   "DirtyArbiter._get_available_workerG  s        ... $T%8%8%B C  !!2!2!45M &&**8Q7C.1Ag]9K-KD  *''C%(1WM0B$BD!3}#5566s   C2C4c                   #    XR                   ;   a  U R                   U   $ U R                  R                  U5      nU(       d  [        SU 35      e[	        S5       HG  n[
        R                  R                  U5      (       a    O0[        R                  " S5      I Sh  vN   MI     [        SU 35      e[        R                  " U5      I Sh  vN u  pEXE4U R                   U'   XE4$  NI N7f)z%Get or create connection to a worker.zNo socket for worker 2   皙?NzWorker socket not ready: )r0   r/   r[   r   ranger$   r+   r   rz   r   open_unix_connection)rB   re   r-   _r   r   s         rC   r   #DirtyArbiter._get_worker_connectionq  s     000**:66))--j94ZLABB rAww~~k**--$$$ 
 8FGG&;;KHH/5.>
+~ % Is$   BC,C(/C,C*C,*C,c                 ~    XR                   ;   a.  U R                   R                  U5      u  p#UR                  5         gg)zClose connection to a worker.N)r0   rj   r   )rB   re   _readerr   s       rC   r   %DirtyArbiter._close_worker_connection  s4    000"5599*EOGLLN 1rF   c                   #    UR                  SS5      n[        R                  " 5       n/ nU R                  R	                  5        He  u  pg UR
                  R                  5       n[        XH-
  S5      n	UR                  UUR                  [        US/ 5      [        USS5      U	S.5        Mg     UR                  S	 S
9  U R                  U[!        U5      U R"                  (       a#  [%        U R"                  R'                  5       5      O/ S.n
[)        X:5      n[*        R,                  " X+5      I Sh  vN   g! [        [        [        4 a    Sn	 Nf = f N"7f)z
Handle a status query request.

Returns information about the dirty arbiter and its workers.

Args:
    message: Status request message
    client_writer: StreamWriter to send response to client
r   r      Nr]   bootedF)r#   ageappsr  last_heartbeatc                     U S   $ )Nr   )ro   s    rC   r   4DirtyArbiter.handle_status_request.<locals>.<lambda>  s    %rF   key)arbiter_pidr.   rI   r  )r[   time	monotonicr.   rY   tmplast_updateroundOSError
ValueErrorAttributeErrorr\   r  getattrsortr#   rZ   r;   rb   r   r   r   r   )rB   r   r   r   nowworkers_infor#   workerr  r  resultr   s               rC   r   "DirtyArbiter.handle_status_request  s0     [[y1
nn<<--/KC&$jj446!&s'8!!< zzR8!&(E:"0!  0 	01  88#-37>>D,,./r	
 !4//HHH+ Z8 &!%&* 	Is7   A	E(D74B=E1E2E7EEEEc                 h  ^ #    UR                  SS5      nUR                  S5      n[        S[        UR                  SS5      5      5      n U[        :X  a  Sn[	        U5       HN  nT R                  5       nUb  T =R                  S-  sl        US-  n[        R                  " S5      I Sh  vN   MP     US:X  a)  S	S
USS[        T R                  5      T R                  S.nGO`S	S
UU[        T R                  5      T R                  S.nGO8U[        :X  a  T R                  5       n	Sn
[	        U5       H  nT R                  U	::  a    O[        T R                  5      S::  a    OT =R                  S-  sl        [        T R                  R                  5       U 4S jS9nT R                  U[         R"                  5        U
S-  n
[        R                  " S5      I Sh  vN   M     S	SUU
[        T R                  5      T R                  S.nO8[%        SU 35      n['        X<5      n[(        R*                  " X-5      I Sh  vN   gT R,                  R/                  SU[        :X  a  S
OSUUR                  SUR                  SS5      5      5        [1        X85      n[(        R*                  " X-5      I Sh  vN   g GN N N~ N! [2         ac  nT R,                  R5                  SU5        ['        U[%        [7        U5      5      5      n[(        R*                  " X-5      I Sh  vN     SnAgSnAff = f7f)z
Handle a worker management request.

Supports adding or removing dirty workers via protocol messages.

Args:
    message: Manage request message
    client_writer: StreamWriter to send response to client
r   r   opr   countr   Nr  Trc   z)All apps have reached their worker limits)success	operation	requestedspawnedreasontotal_workerstarget_workers)r(  r)  r*  r+  r-  r.  c                 6   > TR                   U    R                  $ r   r.   r  prB   s    rC   r   4DirtyArbiter.handle_manage_request.<locals>.<lambda>  s    4<<?3F3FrF   r  remove)r(  r)  r*  removedr-  r.  zUnknown manage operation: z6Worker management: %s %d workers (spawned/removed: %d)r+  r5  zManage operation error: %s)r[   rT   intr   r  spawn_workerr7   rz   r   rZ   r.   r   rV   minr   kill_workerr   r   r   r   r   r   r"   rq   r   rL   r   rt   )rB   r   r   r   r&  r'  r+  r  r#  r   r5  
oldest_pidr   r   rP   s   `              rC   r   "DirtyArbiter.handle_manage_request  s     [[y1
[[As7;;w234N	M]"uA!..0F)((A-(1!--,,, & a<#'%*%*#$"M),T\\):*.*:*:F $(%*%*#*),T\\):*.*:*:F ''"779uA'';64<<(A-$$)$ "%T\\%6%6%8)F"HJ$$Z@qLG!--,,, &   $!)!&&%(%6&*&6&6 #%?t#DE.zA#77PPPHHMMR#%#6%H **Y

9a0HIK
 %Z8H33MLLLA -R - Q M 	MHHNN7;*:z#a&7IJH33MLLL	Ms   A	L2A K -J9.D/K J<A!K ?J> K L2A.K 3K 4K 8L29K <K >K  K 
L/AL*L" L*%L2*L//L2c           	        #    UR                  SS5      nUR                  S5      nUR                  SS5      nUR                  S5      nUR                  S5      nUR                  S5      n S	n	U[        :X  a3  XPR                  ;  a  0 U R                  U'   XpR                  U   U'   S
n	GO{U[        :X  aA  XPR                  ;  a  SS0n	GO\X`R                  U   ;  a  SS0n	GODU R                  U   U   n	GO0U[        :X  a9  XPR                  ;   a&  X`R                  U   ;   a  U R                  U   U	 S
n	GOSn	GOU[
        :X  a}  XPR                  ;  a  / n	GO[        U R                  U   R                  5       5      n
U(       a9  U
 Vs/ s H,  n[        R                  " [        U5      U5      (       d  M*  UPM.     n
nU
n	GOfU[        :X  a0  XPR                  ;   a  U R                  U   R                  5         S
n	GO,U[        :X  a1  XPR                  ;  a  SS0n	GO[        U R                  U   5      US.n	OU[        :X  a!  XPR                  ;  a  0 U R                  U'   S
n	OU[        :X  a"  XPR                  ;   a  U R                  U	 S
n	OSn	OU[         :X  a$  [        U R                  R                  5       5      n	OlU["        :X  a*  XPR                  ;  a  Sn	OPUc  S
n	OJX`R                  U   ;   n	O8[%        SU 35      n['        X<5      n[(        R*                  " X-5      I S	h  vN   g	[-        U	[.        5      (       a~  SU	;   ax  U	S   nUS:X  a  [%        SU 35      nO)US:X  a  [%        SU 35      nO[%        [        U	5      5      nSUR1                  5       R3                  SS5       S3Ul        ['        X<5      nO[7        X95      n[(        R*                  " X-5      I S	h  vN   g	s  snf  N N! [8         ac  nU R:                  R=                  SU5        ['        U[%        [        U5      5      5      n[(        R*                  " X-5      I S	h  vN     S	nAg	S	nAff = f7f)z
Handle a stash operation directly in the arbiter.

All stash tables are stored in arbiter memory for simplicity
and fast access.

Args:
    message: Stash operation message
    client_writer: StreamWriter to send response to client
r   r   r&  table r  valuepatternNTr   key_not_foundFtable_not_found)sizer=  zUnknown stash operation: zTable not found: zKey not found: Stashr  ErrorzStash operation error: %s)r[   r   r@   r   r   r   rb   r   fnmatchrt   r   clearr   rZ   r   r   r   r   r   r   r   r   
isinstancedicttitlereplace
error_typer   rL   r"   r   )rB   r   r   r   r&  r=  r  r?  r@  r#  all_keyskr   r   rL  rP   s                   rC   r   !DirtyArbiter.handle_stash_request  s     [[y1
[[GR(kk% G$++i(a	MF\! 1 11/1D%%e,05!!%(-|# 1 11%7F 1 1% 88%7F!..u5c:F&---#9J9J59Q2Q))%05!F"F}$ 1 11F#D$5$5e$<$A$A$CDH/7 $Ix!'.s1vw'G %&x $I%F~%---%%e,224}$ 1 11%'89F !$D$5$5e$< =!&F
 & 1 11/1D%%e,,,---))%0!F"F&d//4467& 1 11"F[!F $5$5e$<<F #%>rd#CD.zA#77PPP &$''Gv,=#G_
!22&):5''BCE?2&'>?E&s6{3E%*:+;+;+=+E+Ec2+N*Ou#U .zA(<33MLLL{$IX Q" M 	MHHNN6:*:z#a&7IJH33MLLL	Ms   A)Q,DO, )O#4O#:E&O,  O(!O, %Q&B7O, O*O, "Q#O, *O, ,
Q6AQ	Q
QQQQc                   ^ #    T R                   (       d  gT R                  nT R                   (       aw  [        T R                  5      U:  a^  T R	                  5       nUc  OJ[
        R                  " S5      I Sh  vN   T R                   (       a  [        T R                  5      U:  a  M^  [        T R                  5      U:  a  [        T R                  R                  5       U 4S jS9nT R                  U[        R                  5        [
        R                  " S5      I Sh  vN   [        T R                  5      U:  a  M  gg N N#7f)z%Maintain the number of dirty workers.Nr  c                 6   > TR                   U    R                  $ r   r0  r1  s    rC   r   -DirtyArbiter.manage_workers.<locals>.<lambda>  s    4<<?+>+>rF   r  )r5   r7   rZ   r.   r7  rz   r   r8  r   r9  r   r   )rB   r7   r#  r:  s   `   rC   r   DirtyArbiter.manage_workers  s     zz&& jjS.<&&(F~--$$$ jjS.< $,,+-T\\..0!>@JZ8--$$$ $,,+- % %s1   A6E9E:.E*A8E"E#EEEc           	      r   U R                   (       a  U R                   R                  S5      nO;U(       a$  [        U R                  R	                  5       5      nOU R                  5       nU(       d  U R                  R                  S5        gU =R                  S-  sl        [        R                  R                  U R                  SU R                   S35      n[        U R                  U R                  UU R                  U R                  US9n[        R                   " 5       nUS:w  al  XTl        X@R"                  U'   X0R$                  U'   U R'                  XR5        U R                  R)                  X5        U R                  R+                  SXR5        U$ [        R,                  " 5       Ul         [.        R0                  " S	U R                  R2                   S
35        UR5                  5         [        R6                  " S5        g! [8         a9  n[        R6                  " UR:                  b  UR:                  OS5         SnAgSnAf[<         ae    U R                  R?                  S5        UR@                  (       d   [        R6                  " U RB                  5        [        R6                  " S5         gf = f)a  
Spawn a new dirty worker.

Worker app assignment follows these priorities:
1. If there are pending respawns (from dead workers), use those apps
2. Otherwise, determine apps for a new worker based on allocation
3. If force_all_apps=True, spawn with all apps regardless of limits

Args:
    force_all_apps: If True, spawn worker with all apps ignoring limits

Returns:
    Worker PID in parent process, or None if no apps need workers
r   z)No apps need more workers, skipping spawnNr   zworker-z.sock)r  r&   r]   r!   r"   r-   z,Spawned dirty worker (pid: %s) with apps: %szdirty-worker []z!Exception in dirty worker process)"r?   rj   rb   r;   r   r_   r"   r   r4   r$   r+   r,   r*   r   r#   r!   forkr.   r/   rg   dirty_post_forkrq   r%   r   ry   	proc_nameinit_process_exit
SystemExitcoderL   	exceptionr  WORKER_BOOT_ERROR)rB   force_all_appsr]   r-   r"  r#   rP   s          rC   r7  DirtyArbiter.spawn_worker  s     !!..2215IT^^0023I 557IHHNNFG1ggllKK74??"359
 #
 ggi!8J &LL'2$ &&s6HH$$T2HHMMH*J YY[

	0B0B/C1EF!HHQK 	:HHqvv1QVVq99 	HHBC==//0HHQK		s    1AH 
J6/IA/J65J6c                      [         R                  " X5        g! [         a>  nUR                  [        R                  :X  a  U R                  U5         SnAg SnAgSnAff = f)zKill a worker by PID.N)r$   killr  errnoESRCH_cleanup_worker)rB   r#   r   rP   s       rC   r9  DirtyArbiter.kill_worker  sI    	*GGC 	*ww%++%$$S)) &	*s    
A!/AA!c                    U R                  U5        XR                  ;   a*  U R                  U   R                  5         U R                  U	 U R                  R	                  US5        XR
                  ;   a:  [        U R
                  U   5      nU(       a  U R                  R                  U5        U R                  U5        U R                  R	                  US5      nU(       a  U R                  R                  X5        U R                  R	                  US5      nU(       a=  [        R                  R!                  U5      (       a   [        R"                  " U5        ggg! [$         a     gf = f)z
Clean up after a worker exits.

Saves the dead worker's app list to pending respawns so the
replacement worker gets the same apps.
N)r   r2   r   r1   rj   r=   rb   r?   r\   rl   r.   r!   dirty_worker_exitr/   r$   r+   r   r   r  )rB   r#   	dead_appsr"  r-   s        rC   re  DirtyArbiter._cleanup_worker  s+    	%%c* '''!!#&--/%%c* 	sD) %%%T0056I&&--i8 	$!!#t,HH&&t4))--c48277>>+66		+& 7;  s   E   
E-,E-c                 N  #    U R                   R                  (       d  g[        U R                  R	                  5       5       H  u  p [
        R                  " 5       UR                  R                  5       -
  U R                   R                  ::  a  MP   UR                  (       dE  U R                  R                  SU5        SUl        U R                  U[        R                   5        M  U R                  U[        R"                  5        M     g! [        [        4 a     M  f = f7f)z!Kill workers that have timed out.NzDIRTY WORKER TIMEOUT (pid:%s)T)r!   r   rb   r.   rY   r  r  r  r  r  r  abortedr"   criticalr9  r   SIGABRTSIGKILL)rB   r#   r"  s      rC   r   DirtyArbiter.murder_workers  s     xx%% 2 2 45KC>>#fjj&<&<&>>$((BXBXX Y
 >>!!"A3G!%  fnn5  fnn5 6 Z( s,   AD%ADA>D%D"D%!D""D%c                      [         R                  " S[         R                  5      u  pU(       d  gSn[         R                  " U5      (       a  [         R                  " U5      nOM[         R
                  " U5      (       a2  [         R                  " U5      nU R                  R                  SX5        X0R                  :X  a  U R                  R                  SU5        U R                  U5        U R                  R                  SU5        GM  ! [         a)  nUR                  [        R                  :w  a  e  SnAgSnAff = f)zReap dead worker processes.Nz)Dirty worker (pid:%s) killed by signal %sz$Dirty worker failed to boot (pid:%s)zDirty worker exited (pid:%s))r$   waitpidWNOHANG	WIFEXITEDWEXITSTATUSWIFSIGNALEDWTERMSIGr"   rM   r^  r   re  rq   r  rc  ECHILD)rB   wpidstatusexitcoder   rP   s         rC   r   DirtyArbiter.reap_workers*  s    	!zz"bjj9<<''!~~f5H^^F++++f-CHH$$%P%)0 555HHNN#I4P$$T*<dC# $  	ww%,,& '	s   /D CD 
ED<<Ec                   #    U R                   R                  S5        [        U R                  R                  5       H1  nU R                  5         [        R                  " S5      I Sh  vN   M3     [        U R                  R                  5       5      nX R                  R                  S  H#  nU R                  U[        R                  5        M%     g Nk7f)z!Reload workers (SIGHUP handling).zReloading dirty workersr  N)r"   rq   r  r!   r6   r7  rz   r   rb   r.   r   r9  r   r   )rB   r  old_workersr#   s       rC   r   DirtyArbiter.reloadC  s     /0 txx--.A--$$$ /
 4<<,,./xx5567CS&..1 8	 %s   A'C)C*A,Cc                 J  #    U R                   R                  5        H  nUR                  5         M     U(       a  [        R                  O[        R
                  n[        R                  " 5       U R                  R                  -   n[        U R                  R                  5       5       H  nU R                  XS5        M     U R                  (       as  [        R                  " 5       U:  aZ  U R                  5         [        R                  " S5      I Sh  vN   U R                  (       a  [        R                  " 5       U:  a  MZ  [        U R                  R                  5       5       H#  nU R                  U[        R                   5        M%     U R                  5         g N7f)zStop all workers.r  N)r2   rS   r   r   r   r   r  r!   dirty_graceful_timeoutrb   r.   r   r9  r   rz   r   ro  )rB   gracefulr   r   limitr#   s         rC   r   DirtyArbiter.stopQ  s     ))002DKKM 3 !)fnnfnn		dhh=== ))+,CS& - lltyy{U2--$$$ lltyy{U2
 ))+,CS&..1 - %s   DF#F!.F#AF#c                    U R                   (       aO  [        R                  R                  U R                   5      (       a!   [        R                  " U R                   5        [        R                  R                  U R                  5      (       a!   [        R                  " U R                  5         [        R                  " U R                  5       HA  n[        R                  " [        R                  R                  U R                  U5      5        MC     [        R                  " U R                  5        U R                  R                  SU R                  5        g! [
         a     GN	f = f! [
         a     Nf = f! [
         a     NTf = f)zSynchronous cleanup on exit.zDirty arbiter exiting (pid: %s)N)r'   r$   r+   r   r   r  r-   listdirr*   r,   rmdirr"   rq   r#   )rB   r   s     rC   r~   DirtyArbiter._cleanup_synch  s    <<BGGNN4<<88		$,,'
 77>>$**++		$**+
	ZZ,		"'',,t{{A67 -HHT[[! 	7B%      		s7    E  E. 1BE> 
E+*E+.
E;:E;>
F
F)r>   r9   r:   r?   r8   r3   r5   r;   r<   r!   r"   r7   r#   r'   r&   r-   r@   r*   r4   r=   r0   r2   r1   r/   r.   )NNr   )F)T)+__name__
__module____qualname____firstlineno____doc__splitr  r   r   r^  rD   rA   rV   r_   rg   rl   r{   rx   r   r   r|   r   r   r   r   r   r   r   r   r   r   r   r   r   r7  r9  re  r   r   r   r   r~   __static_attributes__).0xr  r   s   0000rC   r   r   1   s    <AACEC 12wvw{+CEG 5 n 5D"6:$B"!@<8<t!
&P((&P2Mh14:Mx(7T*'IR\M|sMj%.FP*"H6&22.CY!Es   B.
r   )%r  rz   rc  rF  r$   r   r(   r  gunicornr   appr   r   errorsr   r   r	   r
   protocolr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r"  r   r   r  rF   rC   <module>r     s]   
    	     @     "  OC OCrF   