U
    ‰d)P  ã                   @   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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eƒZdS )é    N)Ú
HaltServerÚAppImportError)ÚPidfile)ÚsockÚsystemdÚutil)Ú__version__ÚSERVER_SOFTWAREc                   @   sb  e Zd ZdZdZdZi Zg Zi Zg Z	g 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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%dLd3d4„Z&d5d6„ Z'dMd8d9„Z(d:d;„ Z)d<d=„ Z*d>d?„ Z+d@dA„ Z,dBdC„ Z-dDdE„ Z.dFdG„ Z/dHdI„ Z0dJdK„ Z1d1S )NÚ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   ú4/tmp/pip-unpacked-wheel-1tw_qy24/gunicorn/arbiter.pyÚ
<listcomp>,   s   ÿzArbiter.<listcomp>z+HUP QUIT INT TERM TTIN TTOU USR1 USR2 WINCHc                 c   sD   | ]<}|d d… dkr|d dkrt t|ƒ|dd …  ¡ fV  qd S )Nr   ZSIGÚ_)r   r   Úlower)r   Únamer   r   r   Ú	<genexpr>.   s    ÿzArbiter.<genexpr>c                 C   s‚   t tj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)ÚargsÚcwdr   )r	   ÚosÚenvironÚ_num_workersÚ _last_logged_active_worker_countÚlogÚsetupÚpidfiler   Ú
worker_ageÚ
reexec_pidÚ
master_pidÚmaster_namer   ÚgetcwdÚsysÚargvÚinsertÚ
executableÚ	START_CTX)ÚselfÚappr   r   r   r   r   Ú__init__3   s$    

ýzArbiter.__init__c                 C   s   | j S ©N)r   ©r,   r   r   r   Ú_get_num_workersO   s    zArbiter._get_num_workersc                 C   s    | j }|| _ | j | ||¡ d S r/   )r   ÚcfgZnworkers_changed)r,   ÚvalueÚ	old_valuer   r   r   Ú_set_num_workersR   s    zArbiter._set_num_workersc                 C   sâ   || _ |j| _| jd kr(| j |j¡| _dtjk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rÌ| jj ¡ D ]\}}|tj|< q¸| jjrÞ| j  ¡  d S )	NÚGUNICORN_FDzCurrent configuration:
{0}Ú
c                 s   s    | ]\}}d   ||j¡V  qdS )z
  {0}: {1}N)Úformatr3   )r   Úconfigr3   r   r   r   r   j   s   ÿz Arbiter.setup.<locals>.<genexpr>c                 S   s   | d S ©Né   r   )Zsettingr   r   r   Ú<lambda>n   ó    zArbiter.setup.<locals>.<lambda>©Úkey)r-   r2   r   Zlogger_classr   r   Úreopen_filesÚworker_classÚaddressÚworkersÚnum_workersÚtimeoutÚ	proc_nameÚdebugr8   ÚjoinÚsortedÚsettingsÚitemsÚenvZpreload_appZwsgi)r,   r-   ÚkÚvr   r   r   r    X   s.    









ÿýÿzArbiter.setupc                 C   s’  | j  dt¡ dtjkr<ttj d¡ƒ| _| jd | _d| _	t 
¡ | _| jjdk	r„| jj}| jdkrl|d7 }t|ƒ| _| j | j¡ | j | ¡ |  ¡  | jsd}t ¡ }|rÊd| _ttjtj| ƒ}n0| jrúg }tj d¡ d	¡D ]}| t|ƒ¡ qæ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 #| ¡ dS )zS        Initialize the arbiter. Start listening and set pidfile if needed.
        zStarting gunicorn %sÚGUNICORN_PIDz.2zMaster.2Nr   Tr6   ú,c                 S   s   g | ]}t |ƒ‘qS r   ©Ústr©r   Úlr   r   r   r      s     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   r   r   ÚintÚgetr$   rF   r%   ÚgetpidÚpidr2   r!   r   ÚcreateZon_startingÚinit_signalsÚ	LISTENERSr   Ú
listen_fdsÚrangeZSD_LISTEN_FDS_STARTÚpopÚsplitÚappendr   Úcreate_socketsrH   rG   Zworker_class_strZ	sd_notifyÚhasattrrA   rU   Z
when_ready)r,   ZpidnameZfdsr^   ÚfdÚlisteners_strr   r   r   Ústartx   sF    



ÿzArbiter.startc                 C   sz   | j D ]}t |¡ qt ¡  | _ }|D ]}t |¡ t |¡ q(| j ¡  | jD ]}t	 	|| j	¡ qRt	 	t	j
| j¡ dS )z‚        Initialize master signal handling. Most of the signals
        are queued. Child signals only wake up the master.
        N)ÚPIPEr   ÚcloseÚpiper   Zset_non_blockingZclose_on_execr   ÚSIGNALSr   ÚSIGCHLDÚhandle_chld)r,   ÚpÚpairÚsr   r   r   r\   ©   s    



zArbiter.init_signalsc                 C   s&   t | jƒdk r"| j |¡ |  ¡  d S )Né   )ÚlenÚ	SIG_QUEUErb   Úwakeup©r,   ÚsigÚframer   r   r   r   ¿   s    zArbiter.signalc              
   C   sŠ  |   ¡  t d| j ¡ z´|  ¡  |  ¡  | jr<| j d¡nd}|dkrb|  ¡  |  	¡  |  ¡  q"|| j
kr|| j d|¡ q"| j
 |¡}t| d| dƒ}|s¬| j d|¡ q"| j d|¡ |ƒ  |  ¡  q"W n¸ ttfk
rì   |  ¡  Y nš tk
r  } z| j|j|jd W 5 d}~X Y nf tk
r6   ‚ Y nP tk
r„   | jjd	d
d |  d¡ | jdk	rv| j ¡  t d¡ Y nX dS )zMain master loop.úmaster [%s]r   NzIgnoring unknown signal: %sz	handle_%szUnhandled signal: %szHandling signal: %s)ÚreasonÚexit_statusz Unhandled exception in main loopT©Úexc_infoFéÿÿÿÿ)rg   r   Ú_setproctitlerF   Úmanage_workersÚmaybe_promote_masterrs   r`   ÚsleepÚmurder_workersÚ	SIG_NAMESr   rV   rX   r   Úerrorrt   ÚStopIterationÚKeyboardInterruptÚhaltr   ry   rz   Ú
SystemExitÚ	ExceptionÚstopr!   Úunlinkr'   Úexit)r,   rv   ÚsignameÚhandlerÚinstr   r   r   ÚrunÄ   sH    
"ÿ

zArbiter.runc                 C   s   |   ¡  |  ¡  dS )zSIGCHLD handlingN)Úreap_workersrt   ru   r   r   r   rm   ð   s    zArbiter.handle_chldc                 C   s   | j  d| j¡ |  ¡  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   rV   r%   Úreloadr0   r   r   r   Ú
handle_hupõ   s    zArbiter.handle_hupc                 C   s   t ‚dS )zSIGTERM handlingN)r…   r0   r   r   r   Úhandle_termÿ   s    zArbiter.handle_termc                 C   s   |   d¡ t‚dS )zSIGINT handlingFN©rŠ   r…   r0   r   r   r   Ú
handle_int  s    
zArbiter.handle_intc                 C   s   |   d¡ t‚dS )zSIGQUIT handlingFNr•   r0   r   r   r   Úhandle_quit  s    
zArbiter.handle_quitc                 C   s   |  j d7  _ |  ¡  dS )zR        SIGTTIN handling.
        Increases the number of workers by one.
        r;   N©rD   r   r0   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.
        r;   Nr˜   r0   r   r   r   Úhandle_ttou  s    
zArbiter.handle_ttouc                 C   s   | j  ¡  |  tj¡ dS )zU        SIGUSR1 handling.
        Kill all workers by sending them a SIGUSR1
        N)r   r@   Úkill_workersr   ÚSIGUSR1r0   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)Úreexecr0   r   r   r   Úhandle_usr2'  s    zArbiter.handle_usr2c                 C   s8   | j jr(| j d¡ d| _|  tj¡ n| j d¡ dS )zSIGWINCH handlingzgraceful stop of workersr   z SIGWINCH ignored. Not daemonizedN)	r2   Údaemonr   rV   rD   r›   r   ÚSIGTERMrG   r0   r   r   r   Úhandle_winch0  s
    zArbiter.handle_winchc                 C   st   | j dkrd S | j t ¡ krp| j d¡ d| _d| _ | jj| _tjd= | j	d k	r`| j	 
| jj	¡ t d| j ¡ d S )Nr   zMaster has been promoted.r   rO   rx   )r$   r   Úgetppidr   rV   r%   r2   rF   r   r!   Úrenamer   r~   r0   r   r   r   r€   9  s    


zArbiter.maybe_promote_masterc              
   C   sR   zt  | jd d¡ W n6 tk
rL } z|jtjtjfkr<‚ W 5 d}~X Y nX dS )z;        Wake up the arbiter by writing to the PIPE
        r;   ó   .N)r   Úwriterh   ÚIOErrorÚerrnoÚEAGAINÚEINTR)r,   Úer   r   r   rt   J  s
    zArbiter.wakeupNr   c                 C   s\   |   ¡  | j d| j¡ |dk	r.| j d|¡ | jdk	rB| j ¡  | j | ¡ t 	|¡ dS )z halt arbiter zShutting down: %sNz
Reason: %s)
rŠ   r   rV   r%   r!   r‹   r2   Zon_exitr'   rŒ   )r,   ry   rz   r   r   r   r‡   T  s    

zArbiter.haltc              
   C   sª   z>t   | jd gg g d¡}|d s(W dS t | jd d¡r<q(W nf t jtfk
rŠ } z(t|d|jd ƒ}|tj	tj
fkrz‚ W 5 d}~X Y n tk
r¤   t ¡  Y nX dS )zm        Sleep until PIPE is readable or we timeout.
        A readable PIPE means a signal occurred.
        r   g      ð?Nr;   r¨   )Úselectrh   r   Úreadr„   ÚOSErrorr   r   r¨   r©   rª   r†   r'   rŒ   )r,   Úreadyr«   Zerror_numberr   r   r   r   _  s    zArbiter.sleepTc                 C   sš   | j | j  kodkn  o,| j o,| jj }t | j|¡ g | _tj	}|sRtj
}t ¡ | jj }|  |¡ | jrŠt ¡ |k rŠt d¡ ql|  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   çš™™™™™¹?N)r#   r$   r   r2   Ú
reuse_portr   Zclose_socketsr]   r   r¡   ÚSIGQUITÚtimeZgraceful_timeoutr›   ÚWORKERSr   ÚSIGKILL)r,   Zgracefulr‹   rv   Úlimitr   r   r   rŠ   r  s    ÿý
zArbiter.stopc                 C   sê   | j dkr| j d¡ dS | jdkr4| j d¡ dS t ¡ }t ¡ | _ | j dkrTdS | j | ¡ | jj	 
¡ }t|ƒ|d< | jr¢t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.rO   Z
LISTEN_PIDZ
LISTEN_FDSrP   c                 s   s   | ]}t | ¡ ƒV  qd S r/   )rR   ÚfilenorS   r   r   r   r   §  s    z!Arbiter.reexec.<locals>.<genexpr>r6   r   r   )r#   r   Úwarningr$   r   rY   Úforkr2   Zpre_execÚenv_origÚcopyrR   r   rr   r]   rH   Úchdirr+   Úexecvpe)r,   r$   r   r   r   r   rž     s*    




ÿzArbiter.reexecc              	   C   sP  | j j}| j jD ]F}|| j jkr4| j j| tj|< qztj|= W q tk
rT   Y qX q| j ¡  |  	| j¡ | j
 ¡  || j jkrÎ| jD ]}| ¡  qŠt | j | j
¡| _d dd„ | jD ƒ¡}| j
 d|¡ | j  | ¡ | jd k	rî| j ¡  | j jd k	rt| j jƒ| _| j | j¡ t d| j ¡ t| j jƒD ]}|  ¡  q4|  ¡  d S )NrP   c                 S   s   g | ]}t |ƒ‘qS r   rQ   rS   r   r   r   r   Í  s     z"Arbiter.reload.<locals>.<listcomp>zListening at: %srx   )r2   rB   rL   rº   r   r   ÚKeyErrorr-   r’   r    r   r@   r]   ri   r   rc   rH   rV   Z	on_reloadr!   r‹   r   r[   rZ   r   r~   rF   r_   rC   Úspawn_workerr   )r,   Zold_addressrM   rT   rf   r   r   r   r   r’   ¯  s6    





zArbiter.reloadc              
   C   s    | j s
dS t| j ¡ ƒ}|D ]~\}}z t ¡ |j ¡  | j krBW qW n ttfk
r`   Y qY nX |j	sŒ| j
 d|¡ d|_	|  |tj¡ q|  |tj¡ qdS )z)        Kill unused/idle workers
        NzWORKER TIMEOUT (pid:%s)T)rE   Úlistr´   rK   r³   ÚtmpZlast_updater®   Ú
ValueErrorZabortedr   ÚcriticalÚkill_workerr   ÚSIGABRTrµ   )r,   rC   rZ   Úworkerr   r   r   r‚   æ  s    
zArbiter.murder_workersc              
   C   sî   z¸t  dt j¡\}}|sq¶| j|kr,d| _q|d? }|| jkrNd}t|| jƒ‚|| jkrhd}t|| jƒ‚t  |¡rˆ| j 	d|t  
|¡¡ | j |d¡}|sœq|j ¡  | j | |¡ qW n0 tk
rè } z|jtjkrØ‚ W 5 d}~X Y nX dS )z7        Reap workers to avoid zombie processes
        r}   r   é   zWorker failed to boot.zApp failed to load.z2Worker with pid %s was terminated due to signal %sN)r   ÚwaitpidÚWNOHANGr#   ÚWORKER_BOOT_ERRORr   ÚAPP_LOAD_ERRORÚWIFSIGNALEDr   r¸   ÚWTERMSIGr´   r`   rÁ   ri   r2   Z
child_exitr®   r¨   ZECHILD)r,   ÚwpidÚstatusÚexitcodery   rÆ   r«   r   r   r   r‘   û  s6    



ý
zArbiter.reap_workersc                 C   s˜   t | jƒ| jk r|  ¡  | j ¡ }t|dd„ d}t |ƒ| jkr^| d¡\}}|  |tj	¡ q2t |ƒ}| j
|kr”|| _
| jjd |¡d|ddœd	 d
S )z[        Maintain the number of workers by spawning or killing
        as required.
        c                 S   s
   | d j S r:   )Zage)Úwr   r   r   r<   *  r=   z(Arbiter.manage_workers.<locals>.<lambda>r>   r   z{0} workerszgunicorn.workersZgauge)Zmetricr3   Úmtype)ÚextraN)rr   r´   rD   Úspawn_workersrK   rI   r`   rÄ   r   r¡   r   r   rG   r8   )r,   rC   rZ   r   Zactive_worker_countr   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rh||_|| j|< |S | j ¡ D ]}|j ¡  qrt	 ¡ |_zøzDt d| j ¡ | j d|j¡ | j | |¡ | ¡  t d¡ W n® tk
rè   ‚ Y nš tk
rB } z<| jjdd	d
 t d| tj!d tj! "¡  t | j#¡ W 5 d }~X Y n@ tk
r€   | j $d¡ |j%srt | j&¡ t d¡ Y nX W 5 | j d|j¡ z|j ¡  | j | |¡ W n( tk
rÚ   | j dt ¡ ¡ Y nX X d S )Nr;   g       @r   zWorker exiting (pid: %s)z Exception during worker exit:
%szworker [%s]zBooting worker with pid: %sz'Exception while loading the applicationTr{   z%s)ÚfilezException in worker processr}   )'r"   rA   rZ   r]   r-   rE   r2   r   Zpre_forkr   r¹   r´   ÚvaluesrÁ   ri   rY   rV   Úworker_exitr‰   r¸   Ú	tracebackÚ
format_excr   r~   rF   Z	post_forkZinit_processr'   rŒ   rˆ   r   rG   ÚprintÚstderrÚflushrË   Ú	exceptionZbootedrÊ   )r,   rÆ   rZ   Zsiblingr«   r   r   r   r¿   7  sX      þ

ÿ

ÿ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)r_   rD   rr   r´   r¿   r³   r   Úrandom)r,   r   r   r   r   rÔ   e  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Ä   )r,   rv   Zworker_pidsrZ   r   r   r   r›   q  s    zArbiter.kill_workersc                 C   s˜   zt  ||¡ W n‚ tk
r’ } zd|jtjkr€z0| j |¡}|j ¡  | j	 
| |¡ W W Y ¢*dS  ttfk
r~   Y W Y ¢dS X ‚ W 5 d}~X Y nX dS )zj        Kill a worker

        :attr pid: int, worker pid
        :attr sig: `signal.SIG*` value
         N)r   Úkillr®   r¨   ZESRCHr´   r`   rÁ   ri   r2   r×   r¾   )r,   rZ   rv   r«   rÆ   r   r   r   rÄ   z  s    
zArbiter.kill_worker)Nr   )T)2Ú__name__Ú
__module__Ú__qualname__Ú__doc__rÊ   rË   r+   r]   r´   rh   rs   ra   rk   ÚdictÚdirr   rƒ   r.   r1   r5   ÚpropertyrD   r    rg   r\   r   rm   r“   r”   r–   r—   r™   rš   r   rŸ   r¢   r€   rt   r‡   r   rŠ   rž   r’   r‚   r‘   r   r¿   rÔ   r›   rÄ   r   r   r   r   r
      s^   	ÿÿ
 1,

		


"7&.	r
   )r¨   r   rÞ   r¬   r   r'   r³   rØ   Zgunicorn.errorsr   r   Zgunicorn.pidfiler   Zgunicornr   r   r   r   r	   Úobjectr
   r   r   r   r   Ú<module>   s   