o
    À¿i  ã                   @   sš   d dl Z d dlZd dlZd dlZd dl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 d dlmZmZ G dd„ dƒZdS )é    N)Ú
HaltServerÚAppImportError)ÚPidfile)ÚsockÚsystemdÚutil)Ú__version__ÚSERVER_SOFTWAREc                   @   s¶  e Zd ZdZdZdZi Zg Zi Ze	j
Zdd„ d ¡ D ƒZedd„ ee	ƒD ƒƒZd	d
„ Zdd„ Zdd„ ZeeeƒZdd„ Zdd„ Zdd„ Zdd„ Z	dd„ Zdd„ Zdd„ ZeZdd„ Zdd „ Zd!d"„ Zd#d$„ Z d%d&„ Z!d'd(„ Z"d)d*„ Z#d+d,„ Z$d-d.„ Z%d/d0„ Z&d1d2„ Z'dad5d6„Z(dbd8d9„Z)dcd;d<„Z*d=d>„ Z+d?d@„ Z,dAdB„ Z-dCdD„ Z.dEdF„ Z/dGdH„ Z0dIdJ„ Z1dKdL„ Z2dMdN„ Z3dOdP„ Z4dQdR„ Z5dSdT„ Z6dUdV„ Z7dWdX„ Z8dYdZ„ Z9d[d\„ Z:d]d^„ Z;d_d`„ Z<d3S )dÚArbiterz›
    Arbiter maintain the workers processes alive. It launches or
    kills them if needed. It also manages application reloading
    via SIGHUP/USR2.
    é   é   c                 C   s   g | ]	}t td | ƒ‘qS )zSIG%s)ÚgetattrÚsignal)Ú.0Úx© r   úD/home/ubuntu/.local/lib/python3.10/site-packages/gunicorn/arbiter.pyÚ
<listcomp>.   s    ÿzArbiter.<listcomp>z+HUP QUIT INT TERM TTIN TTOU USR1 USR2 WINCHc                 c   sF    | ]}|d d… dkr|d dkrt t|ƒ|dd …  ¡ fV  qd S )Nr   ÚSIGÚ_)r   r   Úlower)r   Únamer   r   r   Ú	<genexpr>0   s   € ÿþzArbiter.<genexpr>c                 C   s´   t tjd< d | _d | _d | _t ¡ | _|  	|¡ d | _
d| _d| _d| _d| _d| _d| _d | _d | _d | _d ddddœ| _t ¡ }tjd d … }| dtj¡ ||tjdœ| _d S )Nr	   Fr   ÚMaster)Ú
start_timeÚworkers_spawnedÚworkers_killedÚreloads)ÚargsÚcwdr   )r	   ÚosÚenvironÚ_num_workersÚ _last_logged_active_worker_countÚlogÚqueueÚSimpleQueueÚ	SIG_QUEUEÚsetupÚpidfiler   Ú
worker_ageÚ
reexec_pidÚ
master_pidÚmaster_nameÚdirty_arbiter_pidÚdirty_arbiterÚdirty_pidfileÚ_control_serverÚ_statsr   ÚgetcwdÚsysÚargvÚinsertÚ
executableÚ	START_CTX)ÚselfÚappr   r   r   r   r   Ú__init__5   s8   


üýzArbiter.__init__c                 C   s   | j S ©N)r"   ©r9   r   r   r   Ú_get_num_workersd   s   zArbiter._get_num_workersc                 C   s    | j }|| _ | j | ||¡ d S r<   )r"   ÚcfgÚnworkers_changed)r9   ÚvalueÚ	old_valuer   r   r   Ú_set_num_workersg   s   zArbiter._set_num_workersc                 C   sæ   || _ |j| _| jd u r| j |j¡| _dtjv r| j ¡  | jj| _| jj| _| jj	| _
| jj| _| jj| _| j d d dd„ t| jj ¡ dd„ dD ƒ¡¡¡ | jjrf| jj ¡ D ]	\}}|tj|< q\| jjrq| j  ¡  d S d S )	NÚGUNICORN_PIDzCurrent configuration:
{0}Ú
c                 s   s"    | ]\}}d   ||j¡V  qdS )z
  {0}: {1}N)ÚformatrA   )r   ÚconfigrA   r   r   r   r      s
   € ÿ
ÿz Arbiter.setup.<locals>.<genexpr>c                 S   s   | d S ©Né   r   )Úsettingr   r   r   Ú<lambda>ƒ   s    zArbiter.setup.<locals>.<lambda>©Úkey)r:   r?   r$   Úlogger_classr    r!   Úreopen_filesÚworker_classÚaddressÚworkersÚnum_workersÚtimeoutÚ	proc_nameÚdebugrF   ÚjoinÚsortedÚsettingsÚitemsÚenvÚpreload_appÚwsgi)r9   r:   ÚkÚvr   r   r   r(   m   s0   









ÿýÿÿzArbiter.setupc                 C   sÒ  | j  dt¡ t ¡ | jd< dtjv r%ttj d¡ƒ| _	| j
d | _
d| _t ¡ | _| jjdurI| jj}| j	dkr=|d7 }t|ƒ| _| j | j¡ | j | ¡ |  ¡  | js–d}t ¡ }|rkd| _ttjtj| ƒ}n| j	rƒg }tj d	¡ d
¡D ]	}| t|ƒ¡ qy| jjrŒttdƒs–t  | j| j |¡| _d
 !dd„ | jD ƒ¡}| j  "d¡ | j  d|| j¡ | j  d| jj#¡ t $d| j ¡ t| j%dƒrÏ| j% &| j| j ¡ | jj'dkrÝ| jj(rÝ|  )¡  |  *¡  | j +| ¡ dS )zS        Initialize the arbiter. Start listening and set pidfile if needed.
        zStarting gunicorn %sr   rD   z.2zMaster.2Nr   TÚGUNICORN_FDú,ÚSO_REUSEPORTc                 S   ó   g | ]}t |ƒ‘qS r   ©Ústr©r   Úlnrr   r   r   r   ¶   ó    z!Arbiter.start.<locals>.<listcomp>zArbiter bootedzListening at: %s (%s)zUsing worker: %sz&READY=1
STATUS=Gunicorn arbiter bootedÚcheck_config),r$   Úinfor   Útimer2   r    r!   ÚintÚgetr,   rU   r-   ÚgetpidÚpidr?   r)   r   ÚcreateÚon_startingÚinit_signalsÚ	LISTENERSr   Ú
listen_fdsÚrangeÚSD_LISTEN_FDS_STARTÚpopÚsplitÚappendÚ
reuse_portÚhasattrÚsocketr   Úcreate_socketsrW   rV   Úworker_class_strÚ	sd_notifyrP   ri   Údirty_workersÚ
dirty_appsÚspawn_dirty_arbiterÚ_start_control_serverÚ
when_ready)r9   ÚpidnameÚfdsrt   ÚfdÚlisteners_strr   r   r   Ústart   sP   



ÿzArbiter.startc                 C   s8   | j  ¡  | jD ]	}t || j¡ qt tj| j¡ dS )z‚        Initialize master signal handling. Most of the signals
        are queued. Child signals only wake up the master.
        N)r$   Úclose_on_execÚSIGNALSr   ÚSIGCHLDÚsignal_chld)r9   Úsr   r   r   rr   É   s   

zArbiter.init_signalsc                 C   ó   | j  |¡ dS )z3Signal handler - NO LOGGING, just queue the signal.N©r'   Ú
put_nowait©r9   ÚsigÚframer   r   r   r   Õ   ó   zArbiter.signalc              
   C   sz  |   ¡  t d| j ¡ zY|  ¡  	 |  ¡  | jddD ]<}|| jvr+| j 	d|¡ q| j 
|¡}t| d| dƒ}|sC| j d|¡ q|tjkrL| jjn| jj	}|d	|ƒ |ƒ  q|  ¡  |  ¡  |  ¡  q ttfyu   |  ¡  Y dS  ty } z| j|j|jd
 W Y d}~dS d}~w ty—   ‚  ty¼   | jjddd |  d¡ | jdur´| j ¡  t d¡ Y dS w )zMain master loop.úmaster [%s]Tç      ð?)rT   zIgnoring unknown signal: %sz	handle_%sNzUnhandled signal: %szHandling signal: %s)ÚreasonÚexit_statusz Unhandled exception in main loop©Úexc_infoFéÿÿÿÿ)r‰   r   Ú_setproctitlerU   Úmanage_workersÚmaybe_promote_masterÚwait_for_signalsÚ	SIG_NAMESr$   rj   rm   r   Úerrorr   rŒ   rV   Úmurder_workersÚmanage_dirty_arbiterÚStopIterationÚKeyboardInterruptÚhaltr   r˜   r™   Ú
SystemExitÚ	ExceptionÚstopr)   Úunlinkr4   Úexit)r9   r“   ÚsignameÚhandlerÚ	log_levelÚinstr   r   r   ÚrunÙ   sL   

ë €ÿ


úzArbiter.runc                 C   r   )z;SIGCHLD signal handler - NO LOGGING, just queue the signal.Nr   r’   r   r   r   r     r•   zArbiter.signal_chldc                 C   s   |   ¡  |  ¡  dS )z6SIGCHLD handling - called from main loop, safe to log.N)Úreap_workersÚreap_dirty_arbiterr=   r   r   r   Úhandle_chld	  s   zArbiter.handle_chldc                 C   s2   | j  d| j¡ |  ¡  | jr|  tj¡ dS dS )z¶        HUP handling.
        - Reload configuration
        - Start the new worker processes with a new configuration
        - Gracefully shutdown the old worker processes
        zHang up: %sN)r$   rj   r-   Úreloadr.   Úkill_dirty_arbiterr   ÚSIGHUPr=   r   r   r   Ú
handle_hup  s
   ÿzArbiter.handle_hupc                 C   s   t ‚)zSIGTERM handling)r¥   r=   r   r   r   Úhandle_term  s   zArbiter.handle_termc                 C   ó   |   d¡ t‚)zSIGINT handlingF©rª   r¥   r=   r   r   r   Ú
handle_int#  ó   
zArbiter.handle_intc                 C   rº   )zSIGQUIT handlingFr»   r=   r   r   r   Úhandle_quit(  r½   zArbiter.handle_quitc                 C   s   |  j d7  _ |  ¡  dS )zR        SIGTTIN handling.
        Increases the number of workers by one.
        rI   N©rS   rž   r=   r   r   r   Úhandle_ttin-  s   zArbiter.handle_ttinc                 C   s(   | j dkrdS |  j d8  _ |  ¡  dS )zR        SIGTTOU handling.
        Decreases the number of workers by one.
        rI   Nr¿   r=   r   r   r   Úhandle_ttou5  s   
zArbiter.handle_ttouc                 C   s0   | j  ¡  |  tj¡ | jr|  tj¡ dS dS )zU        SIGUSR1 handling.
        Kill all workers by sending them a SIGUSR1
        N)r$   rO   Úkill_workersr   ÚSIGUSR1r.   r¶   r=   r   r   r   Úhandle_usr1?  s
   
ÿzArbiter.handle_usr1c                 C   s   |   ¡  dS )zà        SIGUSR2 handling.
        Creates a new arbiter/worker set as a fork of the current
        arbiter without affecting old workers. Use this to do live
        deployment with the ability to backout a change.
        N)Úreexecr=   r   r   r   Úhandle_usr2J  s   zArbiter.handle_usr2c                 C   s:   | j jr| j d¡ d| _|  tj¡ dS | j d¡ dS )zSIGWINCH handlingzgraceful stop of workersr   z SIGWINCH ignored. Not daemonizedN)	r?   Údaemonr$   rj   rS   rÂ   r   ÚSIGTERMrV   r=   r   r   r   Úhandle_winchS  s
   zArbiter.handle_winchc                 C   sx   | j dkrd S | j t ¡ kr:| j d¡ d| _d| _ | jj| _tjd= | j	d ur0| j	 
| jj	¡ t d| j ¡ d S d S )Nr   zMaster has been promoted.r   rD   r–   )r,   r    Úgetppidr$   rj   r-   r?   rU   r!   r)   Úrenamer   r   r=   r   r   r   rŸ   \  s   


õzArbiter.maybe_promote_masterc                 C   s   | j  | j¡ dS )z Wake up the arbiter's main loop.N)r'   r‘   ÚWAKEUP_REQUESTr=   r   r   r   Úwakeupm  s   zArbiter.wakeupNr   c                 C   st   |   ¡  |  ¡  |dkr| jjn| jj}|d| jƒ |dur#|d|ƒ | jdur-| j ¡  | j 	| ¡ t
 |¡ dS )z halt arbiter r   zShutting down: %sNz
Reason: %s)Ú_stop_control_serverrª   r$   rj   r¢   r-   r)   r«   r?   Úon_exitr4   r¬   )r9   r˜   r™   Úlog_funcr   r   r   r§   q  s   


zArbiter.haltr—   c                 C   sš   g }z2| j jd|d}|| jkr| |¡ 	 z| j  ¡ }|| jkr&| |¡ W n tjy3   Y W |S w q tjy?   Y |S  tyL   t 	¡  Y |S w )ze        Wait for signals with timeout.
        Returns a list of signals that were received.
        T)ÚblockrT   )
r'   rm   rÌ   ry   Ú
get_nowaitr%   ÚEmptyr¦   r4   r¬   )r9   rT   Úsignalsr“   r   r   r   r    ‚  s.   




€úûþ
þzArbiter.wait_for_signalsTc                 C   sn  | j | j  kodkn  o| j o| jj }t | j|¡ g | _tj	}|s)tj
}t ¡ | jj }| jr9|  |¡ |  |¡ | }| jsG| jržt ¡ |k rž|s…z,| j ¡ }|tjtj
fv rz| j d¡ d}|  tj
¡ | jrt|  tj
¡ t ¡ d }W n	 ty„   Y nw |  ¡  |  ¡  t d¡ | js˜| jržt ¡ |k sM|  tj¡ | jr­|  tj¡ |  ¡  |  ¡  dS )z°        Stop workers

        :attr graceful: boolean, If True (the default) workers will be
        killed gracefully  (ie. trying to wait for the current connection)
        r   zQuick shutdown requestedTç       @çš™™™™™¹?N)r+   r,   r   r?   rz   r   Úclose_socketsrs   r   rÈ   ÚSIGQUITrk   Úgraceful_timeoutr.   r¶   rÂ   ÚWORKERSr'   rÒ   ÚSIGINTr$   rj   r©   r²   r³   ÚsleepÚSIGKILL)r9   Úgracefulr«   r“   ÚlimitÚquick_shutdownÚpending_sigr   r   r   rª   ›  sN   ÿý


€ÿ
ïzArbiter.stopc                 C   sê   | j dkr| j d¡ dS | jdkr| j d¡ dS t ¡ }t ¡ | _ | j dkr*dS | j | ¡ | jj	 
¡ }t|ƒ|d< | jrQtt ¡ ƒ|d< tt| jƒƒ|d< nd d	d
„ | jD ƒ¡|d< t | jd ¡ t | jd | jd |¡ dS )z1        Relaunch the master and workers.
        r   z"USR2 signal ignored. Child exists.Nz#USR2 signal ignored. Parent exists.rD   Ú
LISTEN_PIDÚ
LISTEN_FDSra   c                 s   s    | ]	}t | ¡ ƒV  qd S r<   )re   Úfilenorf   r   r   r   r   ë  s   € 
ÿz!Arbiter.reexec.<locals>.<genexpr>r`   r   r   )r+   r$   Úwarningr,   r    rn   Úforkr?   Úpre_execÚenv_origÚcopyre   r   Úlenrs   rW   Úchdirr8   Úexecvpe)r9   r,   r!   r   r   r   rÅ   Ñ  s*   




ÿzArbiter.reexecc           	   	   C   sÌ  | j d  d7  < | jj}| jjD ]!}|| jjv r#| jj| tj|< qztj|= W q ty2   Y qw | j 	¡  |  
| j¡ | j ¡  || jjkrn| jD ]}| ¡  qLt | j| j¡| _d dd„ | jD ƒ¡}| j d|¡ | j | ¡ | jd ur~| j ¡  | jjd ur’t| jjƒ| _| j | j¡ t d| j ¡ | j}t| jjƒD ]}|  ¡  q£|   ¡  t! "¡ | jj# }t! "¡ |k rä| j$sÁd S t%dd	„ | j$ &¡ D ƒƒ}||krÓd S |  '¡  t! (d
¡ t! "¡ |k s¼d S d S )Nr   rI   ra   c                 S   rc   r   rd   rf   r   r   r   r     rh   z"Arbiter.reload.<locals>.<listcomp>zListening at: %sr–   c                 s   s    | ]}|j V  qd S r<   ©Úage)r   Úwr   r   r   r   6  s   € z!Arbiter.reload.<locals>.<genexpr>rÖ   ))r2   r?   rQ   r[   rè   r    r!   ÚKeyErrorr:   rµ   r(   r$   rO   rs   Úcloser   r}   rW   rj   Ú	on_reloadr)   r«   r   rp   ro   r   r   rU   r*   ru   rR   Úspawn_workerrž   rk   Ú	monotonicrÙ   rÚ   ÚminÚvaluesr²   rÜ   )	r9   Úold_addressr^   rg   rˆ   Úlast_worker_ager   ÚdeadlineÚoldestr   r   r   rµ   ó  sP   ÿ







øzArbiter.reloadc              
   C   sš   | j sdS t| j ¡ ƒ}|D ]<\}}zt ¡ |j ¡  | j kr!W qW n tt	fy-   Y qw |j
sC| j d|¡ d|_
|  |tj¡ q|  |tj¡ qdS )z)        Kill unused/idle workers
        NzWORKER TIMEOUT (pid:%s)T)rT   ÚlistrÚ   rZ   rk   rô   ÚtmpÚlast_updateÚOSErrorÚ
ValueErrorÚabortedr$   ÚcriticalÚkill_workerr   ÚSIGABRTrÝ   )r9   rR   ro   Úworkerr   r   r   r£   <  s"   ÿÿôzArbiter.murder_workersc           
   
   C   s”  z¯	 t  dt j¡\}}|sW dS | j|krd| _n–d}t  |¡r&t  |¡}nIt  |¡rot  |¡}zt 	|¡j
}W n tyF   d |¡}Y nw d ||¡}|tjkr]|d7 }| j |¡ n|tjkri| j |¡ n| j |¡ |dur|dkr| j d||¡ || jkrŒd	}t|| jƒ‚|| jkr™d
}t|| jƒ‚| j |d¡}|s£q|j ¡  | j | |¡ q tyÉ }	 z|	jtjkr¾‚ W Y d}	~	dS d}	~	ww )z7        Reap workers to avoid zombie processes
        Trœ   r   Nz	signal {}zWorker (pid:{}) was sent {}!z Perhaps out of memory?z$Worker (pid:%s) exited with code %s.zWorker failed to boot.zApp failed to load.)r    ÚwaitpidÚWNOHANGr+   Ú	WIFEXITEDÚWEXITSTATUSÚWIFSIGNALEDÚWTERMSIGr   ÚSignalsr   rÿ   rF   rÝ   r$   r¢   rÈ   rj   rå   ÚWORKER_BOOT_ERRORr   ÚAPP_LOAD_ERRORrÚ   rw   rü   rñ   r?   Ú
child_exitrþ   ÚerrnoÚECHILD)
r9   ÚwpidÚstatusÚexitcoder“   Úsig_nameÚmsgr˜   r  Úer   r   r   r²   Q  s`   



ÿÿ

ÿ


Ð1ÿ€ÿzArbiter.reap_workersc                 C   sî   t | jƒ| jk r|  ¡  | j ¡ }t|dd„ d}t |ƒ| jkr5| d¡\}}|  |tj	¡ t |ƒ| jks t |ƒ}| j
|krP|| _
| jjd |¡d|ddœd	 | jjrstd
d„ | jD ƒƒ}|dkru| jjd |¡d|ddœd	 dS dS dS )z[        Maintain the number of workers by spawning or killing
        as required.
        c                 S   s
   | d j S rH   rí   )rï   r   r   r   rK   ”  s   
 z(Arbiter.manage_workers.<locals>.<lambda>rL   r   z{0} workerszgunicorn.workersÚgauge)ÚmetricrA   Úmtype)Úextrac                 s   s    | ]	}|  ¡ p	d V  qdS )r   N)Úget_backlog)r   r   r   r   r   r   ¢  s   € ÿz)Arbiter.manage_workers.<locals>.<genexpr>zsocket backlog: {0}zgunicorn.backlogÚ	histogramN)rê   rÚ   rS   Úspawn_workersrZ   rX   rw   r  r   rÈ   r#   r$   rV   rF   r?   Úenable_backlog_metricÚsumrs   )r9   rR   ro   r   Úactive_worker_countÚbacklogr   r   r   rž   ‹  s<   
þ
þÿÿþ
ÿûzArbiter.manage_workersc                 C   s~  |  j d7  _ |  | j | j| j| j| jd | j| j¡}| j | |¡ t	 
¡ }|dkr=||_|| j|< | jd  d7  < |S | j ¡ D ]}|j ¡  qBt	 ¡ |_zÅz/t d| j ¡ | j d|j¡ | jjrnt | j| j¡|_| j | |¡ | ¡  t d¡ W nh ty‡   ‚  ty´ } z"| jjddd	 t d
| tj!d tj! "¡  t | j#¡ W Y d }~n8d }~w t$yç } z(| j %d¡ t d
| tj!d tj! "¡  |j&sØt | j'¡ t d¡ W Y d }~nd }~ww W | j d|j¡ z|j ¡  | j (| |¡ W d S  t$y   | j )dt* +¡ ¡ Y d S w | j d|j¡ z|j ¡  | j (| |¡ W w  t$y>   | j )dt* +¡ ¡ Y w w )NrI   rÕ   r   r   zworker [%s]zBooting worker with pid: %sz'Exception while loading the applicationTrš   z%s)ÚfilezException in worker processrœ   zWorker exiting (pid: %s)z Exception during worker exit:
%s),r*   rP   ro   rs   r:   rT   r?   r$   Úpre_forkr    ræ   rÚ   r2   rö   rü   rñ   rn   r   r   rU   rj   rz   r   r}   ÚsocketsÚ	post_forkÚinit_processr4   r¬   r¨   r   rV   ÚprintÚstderrÚflushr  r©   Ú	exceptionÚbootedr  Úworker_exitrå   Ú	tracebackÚ
format_exc)r9   r  ro   Úsiblingr  r   r   r   ró   «  sz   þ

ÿ
€
€ú€

ÿÿü
ÿÿzArbiter.spawn_workerc                 C   s8   t | jt| jƒ ƒD ]}|  ¡  t dt ¡  ¡ q
dS )z‰        Spawn new workers as needed.

        This is where a worker process leaves the main loop
        of the master process.
        rÖ   N)ru   rS   rê   rÚ   ró   rk   rÜ   Úrandom)r9   r   r   r   r   r  Þ  s   þzArbiter.spawn_workersc                 C   s(   t | j ¡ ƒ}|D ]}|  ||¡ q	dS )z^        Kill all workers with the signal `sig`
        :attr sig: `signal.SIG*` value
        N)rû   rÚ   Úkeysr  )r9   r“   Úworker_pidsro   r   r   r   rÂ   ê  s   ÿzArbiter.kill_workersc                 C   sº   zt  ||¡ |tjtjfv r| jd  d7  < W dS W dS  ty\ } z3|jtjkrWz| j	 
|¡}|j ¡  | j | |¡ W W Y d}~dS  ttfyV   Y W Y d}~dS w ‚ d}~ww )zj        Kill a worker

        :attr pid: int, worker pid
        :attr sig: `signal.SIG*` value
         r   rI   N)r    Úkillr   rÈ   rÝ   r2   rþ   r  ÚESRCHrÚ   rw   rü   rñ   r?   r,  rð   )r9   ro   r“   r  r  r   r   r   r  ó  s$   ÿ
ÿ€÷zArbiter.kill_workerc                 C   s8   ddl }| j dd¡ dd¡}tj | ¡ d|› d¡S )a)  Get the well-known PID file path for orphan detection.

        Uses self.proc_name (not self.cfg.proc_name) so that during USR2
        the new master gets a different PID file path ("myapp.2" vs "myapp").
        This prevents the old dirty arbiter from removing the new one's PID file.
        r   Nú/r   ú zgunicorn-dirty-z.pid)ÚtempfilerU   Úreplacer    ÚpathrW   Ú
gettempdir)r9   r7  Ú	safe_namer   r   r   Ú_get_dirty_pidfile_path  s   zArbiter._get_dirty_pidfile_pathc              
   C   s  | j dkrdS |  ¡ }tj |¡sdS zWt|ƒ}t| ¡  ¡ ƒ}W d  ƒ n1 s+w   Y  t 	|d¡ | j
 d|¡ t 	|tj¡ tdƒD ]}t d¡ zt 	|d¡ W qH tya   Y  nw t 	|tj¡ W n tttfyv   Y nw zt |¡ W dS  ty‰   Y dS w )z…Kill any orphaned dirty arbiter from a previous crash.

        Only runs on fresh start (master_pid == 0), not during USR2.
        r   Nz(Killing orphaned dirty arbiter (pid: %s)é
   rÖ   )r,   r<  r    r9  ÚexistsÚopenrl   ÚreadÚstripr3  r$   rå   r   rÈ   ru   rk   rÜ   rþ   rÝ   rÿ   ÚIOErrorr«   )r9   r)   ÚfÚold_pidr   r   r   r   Ú_cleanup_orphaned_dirty_arbiter  s:   

ÿ
ÿ€ÿÿz'Arbiter._cleanup_orphaned_dirty_arbiterc                 C   sÚ   ddl m}m} | jrdS |  ¡  |  ¡ | _|| j| j| jd| _	| j	j
}t ¡ }|dkrC|| _||ƒ |tjd< | j d||¡ |S z| j	 ¡  t d¡ W dS  tyX   ‚  tyl   | j d¡ t d¡ Y dS w )	zž        Spawn the dirty arbiter process.

        The dirty arbiter manages a separate pool of workers for
        long-running, blocking operations.
        r   )ÚDirtyArbiterÚset_dirty_socket_pathN)r)   ÚGUNICORN_DIRTY_SOCKETz%Spawned dirty arbiter (pid: %s) at %sz"Exception in dirty arbiter processrœ   )Úgunicorn.dirtyrF  rG  r.   rE  r<  r0   r?   r$   r/   Úsocket_pathr    ræ   r!   rj   r±   r4   r¬   r¨   r©   r*  )r9   rF  rG  rJ  ro   r   r   r   r‚   A  s8   
þ
ÿ
þzArbiter.spawn_dirty_arbiterc              
   C   sl   | j sdS z
t | j |¡ W dS  ty5 } z|jtjkr*d| _ d| _W Y d}~dS W Y d}~dS d}~ww )z\        Send a signal to the dirty arbiter.

        :attr sig: `signal.SIG*` value
        Nr   )r.   r    r3  rþ   r  r4  r/   )r9   r“   r  r   r   r   r¶   o  s   þ€ÿzArbiter.kill_dirty_arbiterc              
   C   sê   | j sdS zIt | j tj¡\}}|sW dS t |¡r4t |¡}|dkr,| j d||¡ n| j d|¡ nt 	|¡rFt 
|¡}| j d||¡ d| _ d| _W dS  tyt } z|jtjkrid| _ d| _W Y d}~dS W Y d}~dS d}~ww )zA        Reap the dirty arbiter process if it has exited.
        Nr   z*Dirty arbiter (pid:%s) exited with code %szDirty arbiter (pid:%s) exitedz*Dirty arbiter (pid:%s) killed by signal %s)r.   r    r  r  r  r  r$   r¢   rj   r	  r
  rå   r/   rþ   r  r  )r9   r  r  r  r“   r  r   r   r   r³     s6   

ÿ

ÿþ€ÿzArbiter.reap_dirty_arbiterc                 C   s>   | j rdS | jjdkr| jjr| j d¡ |  ¡  dS dS dS )zL        Maintain the dirty arbiter process by respawning if needed.
        Nr   zSpawning dirty arbiter...)r.   r?   r€   r   r$   rj   r‚   r=   r   r   r   r¤   ž  s   þzArbiter.manage_dirty_arbiterc                 C   s*   | j j}tj |¡stj t ¡ |¡}|S )z<Get the control socket path, making relative paths absolute.)r?   Úcontrol_socketr    r9  ÚisabsrW   r   r3   )r9   rJ  r   r   r   Ú_get_control_socket_path­  s   z Arbiter._get_control_socket_pathc              
   C   sŽ   | j jr| j d¡ dS ddlm} |  ¡ }| j j}z|| ||ƒ| _| j 	¡  W dS  t
yF } z| j d|¡ d| _W Y d}~dS d}~ww )z        Start the control socket server.

        The server runs in a background thread and accepts commands
        via Unix socket.
        zControl socket disabledNr   )ÚControlSocketServerz"Failed to start control socket: %s)r?   Úcontrol_socket_disabler$   rV   Úgunicorn.ctl.serverrN  rM  Úcontrol_socket_moder1   r‰   r©   rå   )r9   rN  rJ  Úsocket_moder  r   r   r   rƒ   ´  s    ÿ€þzArbiter._start_control_serverc              
   C   sV   | j r)z| j  ¡  W n ty# } z| j d|¡ W Y d}~nd}~ww d| _ dS dS )z0        Stop the control socket server.
        z!Error stopping control server: %sN)r1   rª   r©   r$   rV   )r9   r  r   r   r   rÎ   Î  s   €ÿ
ûzArbiter._stop_control_server)Nr   )r—   )T)=Ú__name__Ú
__module__Ú__qualname__Ú__doc__r  r  r8   rs   rÚ   r   ÚNSIGrÌ   rx   r‹   ÚdictÚdirr¡   r;   r>   rC   ÚpropertyrS   r(   r‰   rr   r±   r   r´   Ú
handle_cldr¸   r¹   r¼   r¾   rÀ   rÁ   rÄ   rÆ   rÉ   rŸ   rÍ   r§   r    rª   rÅ   rµ   r£   r²   rž   ró   r  rÂ   r  r<  rE  r‚   r¶   r³   r¤   rM  rƒ   rÎ   r   r   r   r   r
      st    	ÿÿ/
 <,
		


6"I: 3	(.r
   )r  r    r%   r0  r   r4   rk   r-  r|   Úgunicorn.errorsr   r   Úgunicorn.pidfiler   Úgunicornr   r   r   r   r	   r
   r   r   r   r   Ú<module>   s   