3
ûZð]þN  ã               @   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jƒ 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-build-w1as9q70/gunicorn/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 … jƒ 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 | _| j|ƒ d | _d| _d| _	d| _
d| _d| _tjƒ }tjd d … }|j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j| ||ƒ d S )N)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|jƒ| _dtjkr<| jjƒ  | jj| _| jj| _| jj	| _
| jj| _| jj| _| jjdjdjdd„ t| jjjƒ dd„ d�D ƒƒƒƒ | jjrÐx"| jjjƒ D ]\}}|tj|< qºW | jjrâ| j jƒ  d S )	NÚGUNICORN_FDzCurrent configuration:
{0}Ú
c             s   s    | ]\}}d j ||jƒV  qdS )z
  {0}: {1}N)Úformatr1   )r   Úconfigr1   r   r   r   r   k   s   z Arbiter.setup.<locals>.<genexpr>c             S   s   | d S )Né   r   )Zsettingr   r   r   Ú<lambda>n   s    zArbiter.setup.<locals>.<lambda>)Úkey)r-   r0   r   Zlogger_classr   r   Úreopen_filesÚworker_classÚaddressÚworkersÚnum_workersÚtimeoutÚ	proc_nameÚdebugr6   ÚjoinÚsortedÚsettingsÚitemsÚenvZpreload_appZwsgi)r,   r-   ÚkÚvr   r   r   r    X   s*    








zArbiter.setupc             C   s˜  | j jdtƒ dtjkr<ttjjdƒƒ| _| jd | _d| _	tj
ƒ | _| jjdk	r„| jj}| jdkrl|d7 }t|ƒ| _| jj| jƒ | jj| ƒ | jƒ  | j�sd}tjƒ }|rÊd| _ttjtj| ƒ}n6| j�r g }x(tjjdƒjd	ƒD ]}|jt|ƒƒ qêW tj| j| j |ƒ| _d	jd
d„ | jD ƒƒ}| j jdƒ | j jd|| jƒ | j jd| jjƒ tjd| j ƒ t | j!dƒ�rˆ| j!j"| 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   Tr4   ú,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$   rA   r%   ÚgetpidÚpidr0   r!   r   ÚcreateZon_startingÚinit_signalsÚ	LISTENERSr   Ú
listen_fdsÚrangeZSD_LISTEN_FDS_STARTÚpopÚsplitÚappendr   Úcreate_socketsrC   rB   Zworker_class_strZ	sd_notifyÚhasattrr<   rN   Z
when_ready)r,   ZpidnameZfdsrW   ÚfdÚlisteners_strr   r   r   Ústartx   sD    



zArbiter.startc             C   s†   x| j D ]}tj|ƒ qW tjƒ  | _ }x |D ]}tj|ƒ tj|ƒ q.W | jjƒ  x| jD ]}t	j	|| j	ƒ q\W t	j	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   rU   ©   s    


zArbiter.init_signalsc             C   s&   t | jƒdk r"| jj|ƒ | jƒ  d S )Né   )ÚlenÚ	SIG_QUEUEr[   Úwakeup)r,   ÚsigÚframer   r   r   r   ¿   s    zArbiter.signalc             C   sŽ  | j ƒ  tjd| j ƒ y¸| jƒ  xª| jƒ  | jr>| jjdƒnd}|dkrd| jƒ  | j	ƒ  | jƒ  q$|| j
kr~| jjd|ƒ q$| j
j|ƒ}t| d| dƒ}|s®| jjd|ƒ q$| jjd|ƒ |ƒ  | jƒ  q$W W n¸ ttfk
rð   | jƒ  Y nš tk
�r$ } z| j|j|jd� W Y dd}~X nf tk
�r:   ‚ Y nP tk
�rˆ   | jjd	d
d� | jdƒ | jdk	�rz| jjƒ  tjdƒ Y nX dS )zMain master loop.z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_infoFr8   éÿÿÿÿ)r`   r   Ú_setproctitlerA   Úmanage_workersÚmaybe_promote_masterrl   rY   ÚsleepÚmurder_workersÚ	SIG_NAMESr   rO   rQ   r   Úerrorrm   ÚStopIterationÚKeyboardInterruptÚhaltr   rp   rq   Ú
SystemExitÚ	ExceptionÚstopr!   Úunlinkr'   Úexit)r,   rn   ZsignameÚhandlerÚinstr   r   r   ÚrunÄ   sH    
"

zArbiter.runc             C   s   | j ƒ  | jƒ  dS )zSIGCHLD handlingN)Úreap_workersrm   )r,   rn   ro   r   r   r   rf   ð   s    zArbiter.handle_chldc             C   s   | j jd| jƒ | 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   rO   r%   Úreload)r,   r   r   r   Ú
handle_hupõ   s    zArbiter.handle_hupc             C   s   t ‚dS )zSIGTERM handlingN)r{   )r,   r   r   r   Úhandle_termÿ   s    zArbiter.handle_termc             C   s   | j dƒ t‚dS )zSIGINT handlingFN)r€   r{   )r,   r   r   r   Ú
handle_int  s    
zArbiter.handle_intc             C   s   | j dƒ t‚dS )zSIGQUIT handlingFN)r€   r{   )r,   r   r   r   Úhandle_quit  s    
zArbiter.handle_quitc             C   s   |  j d7  _ | jƒ  dS )zR        SIGTTIN handling.
        Increases the number of workers by one.
        r8   N)r?   ru   )r,   r   r   r   Úhandle_ttin  s    zArbiter.handle_ttinc             C   s(   | j dkrdS |  j d8  _ | jƒ  dS )zR        SIGTTOU handling.
        Decreases the number of workers by one.
        r8   N)r?   ru   )r,   r   r   r   Úhandle_ttou  s    
zArbiter.handle_ttouc             C   s   | j jƒ  | jtjƒ dS )zU        SIGUSR1 handling.
        Kill all workers by sending them a SIGUSR1
        N)r   r;   Úkill_workersr   ÚSIGUSR1)r,   r   r   r   Úhandle_usr1  s    
zArbiter.handle_usr1c             C   s   | j ƒ  dS )zß        SIGUSR2 handling.
        Creates a new master/worker set as a slave of the current
        master without affecting old workers. Use this to do live
        deployment with the ability to backout a change.
        N)Úreexec)r,   r   r   r   Úhandle_usr2'  s    zArbiter.handle_usr2c             C   s8   | j jr(| jjdƒ d| _| jtjƒ n| jjdƒ dS )zSIGWINCH handlingzgraceful stop of workersr   z SIGWINCH ignored. Not daemonizedN)	r0   Údaemonr   rO   r?   rŽ   r   ÚSIGTERMrB   )r,   r   r   r   Úhandle_winch0  s
    zArbiter.handle_winchc             C   st   | j dkrd S | j tjƒ krp| jjdƒ d| _d| _ | jj| _tjd= | j	d k	r`| j	j
| jj	ƒ tjd| j ƒ d S )Nr   zMaster has been promoted.r   rJ   zmaster [%s])r$   r   Úgetppidr   rO   r%   r0   rA   r   r!   Úrenamer   rt   )r,   r   r   r   rv   9  s    


zArbiter.maybe_promote_masterc             C   sR   yt j| jd dƒ W n6 tk
rL } z|jtjtjgkr<‚ W Y dd}~X nX dS )z;        Wake up the arbiter by writing to the PIPE
        r8   ó   .N)r   Úwritera   ÚIOErrorÚerrnoÚEAGAINÚEINTR)r,   Úer   r   r   rm   J  s
    zArbiter.wakeupNr   c             C   s\   | j ƒ  | jjd| jƒ |dk	r.| jjd|ƒ | jdk	rB| jjƒ  | jj| ƒ tj	|ƒ dS )z halt arbiter zShutting down: %sNz
Reason: %s)
r€   r   rO   r%   r!   r�   r0   Zon_exitr'   r‚   )r,   rp   rq   r   r   r   r}   T  s    

zArbiter.haltc             C   s¬   y@t j | jd gg g dƒ}|d s&dS xtj| jd dƒr<q(W W nf t jtfk
rŒ } z*t|d|jd ƒ}|tj	tj
gkr|‚ W Y dd}~X n tk
r¦   tjƒ  Y nX dS )zm        Sleep until PIPE is readable or we timeout.
        A readable PIPE means a signal occurred.
        r   g      ð?Nr8   r›   )Úselectra   r   Úreadrz   ÚOSErrorr   r   r›   rœ   r�   r|   r'   r‚   )r,   Úreadyrž   Zerror_numberr   r   r   rw   _  s    zArbiter.sleepTc             C   sž   | j | j  kodkn  o,| j o,| jj }tj| j|ƒ g | _tj	}|sRtj
}tjƒ | jj }| j|ƒ x | jrŒtjƒ |k rŒtjdƒ qnW | j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   gš™™™™™¹?N)r#   r$   r   r0   Z
reuse_portr   Zclose_socketsrV   r   r”   ÚSIGQUITÚtimeZgraceful_timeoutrŽ   ÚWORKERSrw   ÚSIGKILL)r,   Zgracefulr�   rn   Úlimitr   r   r   r€   r  s    

zArbiter.stopc             C   sê   | j dkr| jjdƒ dS | jdkr4| jjdƒ dS tjƒ }tjƒ | _ | j dkrTdS | jj| ƒ | jj	j
ƒ }t|ƒ|d< | jr¢ttjƒ ƒ|d< tt| jƒƒ|d< ndjd	d
„ | jD ƒƒ|d< tj| jd ƒ tj| 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.rJ   Z
LISTEN_PIDZ
LISTEN_FDSrK   c             s   s   | ]}t |jƒ ƒV  qd S )N)rL   Úfileno)r   rM   r   r   r   r   ¨  s    z!Arbiter.reexec.<locals>.<genexpr>r4   r   r   )r#   r   Úwarningr$   r   rR   Úforkr0   Zpre_execÚenv_origÚcopyrL   r   rk   rV   rC   Úchdirr+   Úexecvpe)r,   r$   r   r   r   r   r‘   �  s(    



zArbiter.reexecc             C   s\  | j j}xR| j jD ]F}|| j jkr6| j j| tj|< qytj|= W q tk
rV   Y qX qW | jjƒ  | j	| jƒ | j
jƒ  || j jkrÖx| jD ]}|jƒ  q�W tj| j | j
ƒ| _djdd„ | jD ƒƒ}| j
jd|ƒ | j j| ƒ | jd k	rö| jjƒ  | j jd k	�r t| j jƒ| _| jj| jƒ tjd| j ƒ xt| j jƒD ]}| jƒ  �q>W | jƒ  d S )NrK   c             S   s   g | ]}t |ƒ‘qS r   )rL   )r   rM   r   r   r   r   Í  s    z"Arbiter.reload.<locals>.<listcomp>zListening at: %szmaster [%s])r0   r=   rG   r«   r   r   ÚKeyErrorr-   r‡   r    r   r;   rV   rb   r   r\   rC   rO   Z	on_reloadr!   r�   r   rT   rS   r   rt   rA   rX   r>   Úspawn_workerru   )r,   Zold_addressrH   rM   r_   r   r   r   r   r‡   ¯  s6    




zArbiter.reloadc             C   s    | j s
dS t| jjƒ ƒ}x‚|D ]z\}}ytjƒ |jjƒ  | j krBwW n ttfk
r^   wY nX |j	sŠ| j
jd|ƒ d|_	| j|tjƒ q| j|tjƒ qW dS )z)        Kill unused/idle workers
        NzWORKER TIMEOUT (pid:%s)T)r@   Úlistr¥   rF   r¤   ÚtmpZlast_updater¡   Ú
ValueErrorZabortedr   ÚcriticalÚkill_workerr   ÚSIGABRTr¦   )r,   r>   rS   Úworkerr   r   r   rx   æ  s    zArbiter.murder_workersc             C   sÒ   yœx–t jdt jƒ\}}|sP | j|kr.d| _q|d? }|| jkrPd}t|| jƒ‚|| jkrjd}t|| jƒ‚| jj|dƒ}|s~q|j	j
ƒ  | jj| |ƒ qW W n0 tk
rÌ } z|jtjkr¼‚ W Y dd}~X nX dS )z7        Reap workers to avoid zombie processes
        r8   r   é   zWorker failed to boot.zApp failed to load.Nrs   )r   ÚwaitpidÚWNOHANGr#   ÚWORKER_BOOT_ERRORr   ÚAPP_LOAD_ERRORr¥   rY   r²   rb   r0   Z
child_exitr¡   r›   ZECHILD)r,   ÚwpidÚstatusÚexitcoderp   r·   rž   r   r   r   r†   û  s,    



zArbiter.reap_workersc             C   sœ   t | jƒ| jk r| jƒ  | jjƒ }t|dd„ d�}x.t |ƒ| jkr`|jdƒ\}}| j|tj	ƒ q4W t |ƒ}| j
|kr˜|| _
| jjdj|ƒd|ddœd	� d
S )z[        Maintain the number of workers by spawning or killing
        as required.
        c             S   s
   | d j S )Nr8   )Zage)Úwr   r   r   r9   $  s    z(Arbiter.manage_workers.<locals>.<lambda>)r:   r   z{0} workerszgunicorn.workersZgauge)Zmetricr1   Úmtype)ÚextraN)rk   r¥   r?   Úspawn_workersrF   rD   rY   rµ   r   r”   r   r   rB   r6   )r,   r>   rS   r   Zactive_worker_countr   r   r   ru     s    

zArbiter.manage_workersc             C   sÒ  |  j d7  _ | j| j | j| j| j| jd | j| jƒ}| jj| |ƒ t	j
ƒ }|dkrh||_|| j|< |S x| jjƒ D ]}|jjƒ  qtW t	jƒ |_zîyDtjd| j ƒ | jjd|jƒ | jj| |ƒ |jƒ  tjdƒ W n¤ tk
rì   ‚ Y n� tk
�rF } z>| jjddd� td	| tjd
� tjjƒ  tj| jƒ W Y d d }~X n6   | jjdƒ |j �sltj| j!ƒ tjdƒ Y nX W d | jjd|jƒ y|jjƒ  | jj"| |ƒ W n   | jj#dt$j%ƒ ƒ Y nX X d S )Nr8   g       @r   zworker [%s]zBooting worker with pid: %sz'Exception while loading the applicationT)rr   z%s)ÚfilezException in worker processzWorker exiting (pid: %s)z Exception during worker exit:
%srs   )&r"   r<   rS   rV   r-   r@   r0   r   Zpre_forkr   rª   r¥   Úvaluesr²   rb   rR   r   rt   rA   rO   Z	post_forkZinit_processr'   r‚   r~   r   rB   ÚprintÚstderrÚflushr¼   Ú	exceptionZbootedr»   Úworker_exitr©   Ú	tracebackÚ
format_exc)r,   r·   rS   Zsiblingrž   r   r   r   r°   1  sN    



zArbiter.spawn_workerc             C   s<   x6t | jt| jƒ ƒD ]}| jƒ  tjdtjƒ  ƒ qW dS )z‰        Spawn new workers as needed.

        This is where a worker process leaves the main loop
        of the master process.
        gš™™™™™¹?N)rX   r?   rk   r¥   r°   r¤   rw   Úrandom)r,   r   r   r   r   rÃ   _  s    zArbiter.spawn_workersc             C   s,   t | jjƒ ƒ}x|D ]}| j||ƒ qW dS )z^        Kill all workers with the signal `sig`
        :attr sig: `signal.SIG*` value
        N)r±   r¥   Úkeysrµ   )r,   rn   Zworker_pidsrS   r   r   r   rŽ   k  s    
zArbiter.kill_workersc             C   sˆ   yt j||ƒ W nr tk
r‚ } zV|jtjkrpy(| jj|ƒ}|jjƒ  | j	j
| |ƒ dS  ttfk
rn   dS X ‚ W Y dd}~X nX dS )zj        Kill a worker

        :attr pid: int, worker pid
        :attr sig: `signal.SIG*` value
         N)r   Úkillr¡   r›   ZESRCHr¥   rY   r²   rb   r0   rÊ   r¯   )r,   rS   rn   rž   r·   r   r   r   rµ   t  s    
zArbiter.kill_worker)Nr   )T)2Ú__name__Ú
__module__Ú__qualname__Ú__doc__r»   r¼   r+   rV   r¥   ra   rl   rZ   rd   ÚdictÚdirr   ry   r.   r/   r3   Úpropertyr?   r    r`   rU   r…   rf   rˆ   r‰   rŠ   r‹   rŒ   r�   r�   r’   r•   rv   rm   r}   rw   r€   r‘   r‡   rx   r†   ru   r°   rÃ   rŽ   rµ   r   r   r   r   r
      sZ   
 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   