<s> from __future__ import print_function <EOL> import errno <EOL> import os <EOL> import random <EOL> import select <EOL> import signal <EOL> import sys <EOL> import time <EOL> import traceback <EOL> from gunicorn . errors import HaltServer , AppImportError <EOL> from gunicorn . pidfile import Pidfile <EOL> from gunicorn . sock import create_sockets <EOL> from gunicorn import util <EOL> from gunicorn import __version__ , SERVER_SOFTWARE <EOL> class Arbiter ( object ) : <EOL> """<STR_LIT>""" <EOL> WORKER_BOOT_ERROR = <NUM_LIT:3> <EOL> APP_LOAD_ERROR = <NUM_LIT:4> <EOL> START_CTX = { } <EOL> LISTENERS = [ ] <EOL> WORKERS = { } <EOL> PIPE = [ ] <EOL> SIG_QUEUE = [ ] <EOL> SIGNALS = [ getattr ( signal , "<STR_LIT>" % x ) <EOL> for x in "<STR_LIT>" . split ( ) ] <EOL> SIG_NAMES = dict ( <EOL> ( getattr ( signal , name ) , name [ <NUM_LIT:3> : ] . lower ( ) ) for name in dir ( signal ) <EOL> if name [ : <NUM_LIT:3> ] == "<STR_LIT>" and name [ <NUM_LIT:3> ] != "<STR_LIT:_>" <EOL> ) <EOL> def __init__ ( self , app ) : <EOL> os . environ [ "<STR_LIT>" ] = SERVER_SOFTWARE <EOL> self . _num_workers = None <EOL> self . _last_logged_active_worker_count = None <EOL> self . log = None <EOL> self . setup ( app ) <EOL> self . pidfile = None <EOL> self . worker_age = <NUM_LIT:0> <EOL> self . reexec_pid = <NUM_LIT:0> <EOL> self . master_name = "<STR_LIT>" <EOL> cwd = util . getcwd ( ) <EOL> args = sys . argv [ : ] <EOL> args . insert ( <NUM_LIT:0> , sys . executable ) <EOL> self . START_CTX = { <EOL> "<STR_LIT:args>" : args , <EOL> "<STR_LIT>" : cwd , <EOL> <NUM_LIT:0> : sys . executable <EOL> } <EOL> def _get_num_workers ( self ) : <EOL> return self . _num_workers <EOL> def _set_num_workers ( self , value ) : <EOL> old_value = self . _num_workers <EOL> self . _num_workers = value <EOL> self . cfg . nworkers_changed ( self , value , old_value ) <EOL> num_workers = property ( _get_num_workers , _set_num_workers ) <EOL> def setup ( self , app ) : <EOL> self . app = app <EOL> self . cfg = app . cfg <EOL> if self . log is None : <EOL> self . log = self . cfg . logger_class ( app . cfg ) <EOL> if '<STR_LIT>' in os . environ : <EOL> self . log . reopen_files ( ) <EOL> self . worker_class = self . cfg . worker_class <EOL> self . address = self . cfg . address <EOL> self . num_workers = self . cfg . workers <EOL> self . timeout = self . cfg . timeout <EOL> self . proc_name = self . cfg . proc_name <EOL> self . log . debug ( '<STR_LIT>' . format ( <EOL> '<STR_LIT:\n>' . join ( <EOL> '<STR_LIT>' . format ( config , value . value ) <EOL> for config , value <EOL> in sorted ( self . cfg . settings . items ( ) , <EOL> key = lambda setting : setting [ <NUM_LIT:1> ] ) ) ) ) <EOL> if self . cfg . env : <EOL> for k , v in self . cfg . env . items ( ) : <EOL> os . environ [ k ] = v <EOL> if self . cfg . preload_app : <EOL> self . app . wsgi ( ) <EOL> def start ( self ) : <EOL> """<STR_LIT>""" <EOL> self . log . info ( "<STR_LIT>" , __version__ ) <EOL> self . pid = os . getpid ( ) <EOL> if self . cfg . pidfile is not None : <EOL> self . pidfile = Pidfile ( self . cfg . pidfile ) <EOL> self . pidfile . create ( self . pid ) <EOL> self . cfg . on_starting ( self ) <EOL> self . init_signals ( ) <EOL> if not self . LISTENERS : <EOL> self . LISTENERS = create_sockets ( self . cfg , self . log ) <EOL> listeners_str = "<STR_LIT:U+002C>" . join ( [ str ( l ) for l in self . LISTENERS ] ) <EOL> self . log . debug ( "<STR_LIT>" ) <EOL> self . log . info ( "<STR_LIT>" , listeners_str , self . pid ) <EOL> self . log . info ( "<STR_LIT>" , self . cfg . worker_class_str ) <EOL> if hasattr ( self . worker_class , "<STR_LIT>" ) : <EOL> self . worker_class . check_config ( self . cfg , self . log ) <EOL> self . cfg . when_ready ( self ) <EOL> def init_signals ( self ) : <EOL> """<STR_LIT>""" <EOL> if self . PIPE : <EOL> [ os . close ( p ) for p in self . PIPE ] <EOL> self . PIPE = pair = os . pipe ( ) <EOL> for p in pair : <EOL> util . set_non_blocking ( p ) <EOL> util . close_on_exec ( p ) <EOL> self . log . close_on_exec ( ) <EOL> [ signal . signal ( s , self . signal ) for s in self . SIGNALS ] <EOL> signal . signal ( signal . SIGCHLD , self . handle_chld ) <EOL> def signal ( self , sig , frame ) : <EOL> if len ( self . SIG_QUEUE ) < <NUM_LIT:5> : <EOL> self . SIG_QUEUE . append ( sig ) <EOL> self . wakeup ( ) <EOL> def run ( self ) : <EOL> "<STR_LIT>" <EOL> self . start ( ) <EOL> util . _setproctitle ( "<STR_LIT>" % self . proc_name ) <EOL> try : <EOL> self . manage_workers ( ) <EOL> while True : <EOL> sig = self . SIG_QUEUE . pop ( <NUM_LIT:0> ) if len ( self . SIG_QUEUE ) else None <EOL> if sig is None : <EOL> self . sleep ( ) <EOL> self . murder_workers ( ) <EOL> self . manage_workers ( ) <EOL> continue <EOL> if sig not in self . SIG_NAMES : <EOL> self . log . info ( "<STR_LIT>" , sig ) <EOL> continue <EOL> signame = self . SIG_NAMES . get ( sig ) <EOL> handler = getattr ( self , "<STR_LIT>" % signame , None ) <EOL> if not handler : <EOL> self . log . error ( "<STR_LIT>" , signame ) <EOL> continue <EOL> self . log . info ( "<STR_LIT>" , signame ) <EOL> handler ( ) <EOL> self . wakeup ( ) <EOL> except StopIteration : <EOL> self . halt ( ) <EOL> except KeyboardInterrupt : <EOL> self . halt ( ) <EOL> except HaltServer as inst : <EOL> self . halt ( reason = inst . reason , exit_status = inst . exit_status ) <EOL> except SystemExit : <EOL> raise <EOL> except Exception : <EOL> self . log . info ( "<STR_LIT>" , <EOL> traceback . format_exc ( ) ) <EOL> self . stop ( False ) <EOL> if self . pidfile is not None : <EOL> self . pidfile . unlink ( ) <EOL> sys . exit ( - <NUM_LIT:1> ) <EOL> def handle_chld ( self , sig , frame ) : <EOL> "<STR_LIT>" <EOL> self . reap_workers ( ) <EOL> self . wakeup ( ) <EOL> def handle_hup ( self ) : <EOL> """<STR_LIT>""" <EOL> self . log . info ( "<STR_LIT>" , self . master_name ) <EOL> self . reload ( ) <EOL> def handle_term ( self ) : <EOL> "<STR_LIT>" <EOL> raise StopIteration <EOL> def handle_int ( self ) : <EOL> "<STR_LIT>" <EOL> self . stop ( False ) <EOL> raise StopIteration <EOL> def handle_quit ( self ) : <EOL> "<STR_LIT>" <EOL> self . stop ( False ) <EOL> raise StopIteration <EOL> def handle_ttin ( self ) : <EOL> """<STR_LIT>""" <EOL> self . num_workers += <NUM_LIT:1> <EOL> self . manage_workers ( ) <EOL> def handle_ttou ( self ) : <EOL> """<STR_LIT>""" <EOL> if self . num_workers <= <NUM_LIT:1> : <EOL> return <EOL> self . num_workers -= <NUM_LIT:1> <EOL> self . manage_workers ( ) <EOL> def handle_usr1 ( self ) : <EOL> """<STR_LIT>""" <EOL> self . log . reopen_files ( ) <EOL> self . kill_workers ( signal . SIGUSR1 ) <EOL> def handle_usr2 ( self ) : <EOL> """<STR_LIT>""" <EOL> self . reexec ( ) <EOL> def handle_winch ( self ) : <EOL> "<STR_LIT>" <EOL> if self . cfg . daemon : <EOL> self . log . info ( "<STR_LIT>" ) <EOL> self . num_workers = <NUM_LIT:0> <EOL> self . kill_workers ( signal . SIGTERM ) <EOL> else : <EOL> self . log . debug ( "<STR_LIT>" ) <EOL> def wakeup ( self ) : <EOL> """<STR_LIT>""" <EOL> try : <EOL> os . write ( self . PIPE [ <NUM_LIT:1> ] , b'<STR_LIT:.>' ) <EOL> except IOError as e : <EOL> if e . errno not in [ errno . EAGAIN , errno . EINTR ] : <EOL> raise <EOL> def halt ( self , reason = None , exit_status = <NUM_LIT:0> ) : <EOL> """<STR_LIT>""" <EOL> self . stop ( ) <EOL> self . log . info ( "<STR_LIT>" , self . master_name ) <EOL> if reason is not None : <EOL> self . log . info ( "<STR_LIT>" , reason ) <EOL> if self . pidfile is not None : <EOL> self . pidfile . unlink ( ) <EOL> self . cfg . on_exit ( self ) <EOL> sys . exit ( exit_status ) <EOL> def sleep ( self ) : <EOL> """<STR_LIT>""" <EOL> try : <EOL> ready = select . select ( [ self . PIPE [ <NUM_LIT:0> ] ] , [ ] , [ ] , <NUM_LIT:1.0> ) <EOL> if not ready [ <NUM_LIT:0> ] : <EOL> return <EOL> while os . read ( self . PIPE [ <NUM_LIT:0> ] , <NUM_LIT:1> ) : <EOL> pass <EOL> except select . error as e : <EOL> if e . args [ <NUM_LIT:0> ] not in [ errno . EAGAIN , errno . EINTR ] : <EOL> raise <EOL> except OSError as e : <EOL> if e . errno not in [ errno . EAGAIN , errno . EINTR ] : <EOL> raise <EOL> except KeyboardInterrupt : <EOL> sys . exit ( ) <EOL> def stop ( self , graceful = True ) : <EOL> """<STR_LIT>""" <EOL> self . LISTENERS = [ ] <EOL> sig = signal . SIGTERM <EOL> if not graceful : <EOL> sig = signal . SIGQUIT <EOL> limit = time . time ( ) + self . cfg . graceful_timeout <EOL> self . kill_workers ( sig ) <EOL> while self . WORKERS and time . time ( ) < limit : <EOL> time . sleep ( <NUM_LIT:0.1> ) <EOL> self . kill_workers ( signal . SIGKILL ) <EOL> def reexec ( self ) : <EOL> """<STR_LIT>""" <EOL> if self . pidfile is not None : <EOL> self . pidfile . rename ( "<STR_LIT>" % self . pidfile . fname ) <EOL> self . reexec_pid = os . fork ( ) <EOL> if self . reexec_pid != <NUM_LIT:0> : <EOL> self . master_name = "<STR_LIT>" <EOL> return <EOL> environ = self . cfg . env_orig . copy ( ) <EOL> fds = [ l . fileno ( ) for l in self . LISTENERS ] <EOL> environ [ '<STR_LIT>' ] = "<STR_LIT:U+002C>" . join ( [ str ( fd ) for fd in fds ] ) <EOL> os . chdir ( self . START_CTX [ '<STR_LIT>' ] ) <EOL> self . cfg . pre_exec ( self ) <EOL> os . execvpe ( self . START_CTX [ <NUM_LIT:0> ] , self . START_CTX [ '<STR_LIT:args>' ] , environ ) <EOL> def reload ( self ) : <EOL> old_address = self . cfg . address <EOL> for k in self . cfg . env : <EOL> if k in self . cfg . env_orig : <EOL> os . environ [ k ] = self . cfg . env_orig [ k ] <EOL> else : <EOL> try : <EOL> del os . environ [ k ] <EOL> except KeyError : <EOL> pass <EOL> self . app . reload ( ) <EOL> self . setup ( self . app ) <EOL> self . log . reopen_files ( ) <EOL> if old_address != self . cfg . address : <EOL> [ l . close ( ) for l in self . LISTENERS ] <EOL> self . LISTENERS = create_sockets ( self . cfg , self . log ) <EOL> self . log . info ( "<STR_LIT>" , "<STR_LIT:U+002C>" . join ( str ( self . LISTENERS ) ) ) <EOL> self . cfg . on_reload ( self ) <EOL> if self . pidfile is not None : <EOL> self . pidfile . unlink ( ) <EOL> if self . cfg . pidfile is not None : <EOL> self . pidfile = Pidfile ( self . cfg . pidfile ) <EOL> self . pidfile . create ( self . pid ) <EOL> util . _setproctitle ( "<STR_LIT>" % self . proc_name ) <EOL> for i in range ( self . cfg . workers ) : <EOL> self . spawn_worker ( ) <EOL> self . manage_workers ( ) <EOL> def murder_workers ( self ) : <EOL> """<STR_LIT>""" <EOL> if not self . timeout : <EOL> return <EOL> workers = list ( self . WORKERS . items ( ) ) <EOL> for ( pid , worker ) in workers : <EOL> try : <EOL> if time . time ( ) - worker . tmp . last_update ( ) <= self . timeout : <EOL> continue <EOL> except ( OSError , ValueError ) : <EOL> continue <EOL> if not worker . aborted : <EOL> self . log . critical ( "<STR_LIT>" , pid ) <EOL> worker . aborted = True <EOL> self . kill_worker ( pid , signal . SIGABRT ) <EOL> else : <EOL> self . kill_worker ( pid , signal . SIGKILL ) <EOL> def reap_workers ( self ) : <EOL> """<STR_LIT>""" <EOL> try : <EOL> while True : <EOL> wpid , status = os . waitpid ( - <NUM_LIT:1> , os . WNOHANG ) <EOL> if not wpid : <EOL> break <EOL> if self . reexec_pid == wpid : <EOL> self . reexec_pid = <NUM_LIT:0> <EOL> else : <EOL> exitcode = status >> <NUM_LIT:8> <EOL> if exitcode == self . WORKER_BOOT_ERROR : <EOL> reason = "<STR_LIT>" <EOL> raise HaltServer ( reason , self . WORKER_BOOT_ERROR ) <EOL> if exitcode == self . APP_LOAD_ERROR : <EOL> reason = "<STR_LIT>" <EOL> raise HaltServer ( reason , self . APP_LOAD_ERROR ) <EOL> worker = self . WORKERS . pop ( wpid , None ) <EOL> if not worker : <EOL> continue <EOL> worker . tmp . close ( ) <EOL> except OSError as e : <EOL> if e . errno != errno . ECHILD : <EOL> raise <EOL> def manage_workers ( self ) : <EOL> """<STR_LIT>""" <EOL> if len ( self . WORKERS . keys ( ) ) < self . num_workers : <EOL> self . spawn_workers ( ) <EOL> workers = self . WORKERS . items ( ) <EOL> workers = sorted ( workers , key = lambda w : w [ <NUM_LIT:1> ] . age ) <EOL> while len ( workers ) > self . num_workers : <EOL> ( pid , _ ) = workers . pop ( <NUM_LIT:0> ) <EOL> self . kill_worker ( pid , signal . SIGTERM ) <EOL> active_worker_count = len ( workers ) <EOL> if self . _last_logged_active_worker_count != active_worker_count : <EOL> self . _last_logged_active_worker_count = active_worker_count <EOL> self . log . debug ( "<STR_LIT>" . format ( active_worker_count ) , <EOL> extra = { "<STR_LIT>" : "<STR_LIT>" , <EOL> "<STR_LIT:value>" : active_worker_count , <EOL> "<STR_LIT>" : "<STR_LIT>" } ) <EOL> def spawn_worker ( self ) : <EOL> self . worker_age += <NUM_LIT:1> <EOL> worker = self . worker_class ( self . worker_age , self . pid , self . LISTENERS , <EOL> self . app , self . timeout / <NUM_LIT> , <EOL> self . cfg , self . log ) <EOL> self . cfg . pre_fork ( self , worker ) <EOL> pid = os . fork ( ) <EOL> if pid != <NUM_LIT:0> : <EOL> self . WORKERS [ pid ] = worker <EOL> return pid <EOL> worker_pid = os . getpid ( ) <EOL> try : <EOL> util . _setproctitle ( "<STR_LIT>" % self . proc_name ) <EOL> self . log . info ( "<STR_LIT>" , worker_pid ) <EOL> self . cfg . post_fork ( self , worker ) <EOL> worker . init_process ( ) <EOL> sys . exit ( <NUM_LIT:0> ) <EOL> except SystemExit : <EOL> raise <EOL> except AppImportError as e : <EOL> self . log . debug ( "<STR_LIT>" , <EOL> traceback . format_exc ( ) ) <EOL> print ( "<STR_LIT:%s>" % e , file = sys . stderr ) <EOL> sys . stderr . flush ( ) <EOL> sys . exit ( self . APP_LOAD_ERROR ) <EOL> except : <EOL> self . log . exception ( "<STR_LIT>" , <EOL> traceback . format_exc ( ) ) <EOL> if not worker . booted : <EOL> sys . exit ( self . WORKER_BOOT_ERROR ) <EOL> sys . exit ( - <NUM_LIT:1> ) <EOL> finally : <EOL> self . log . info ( "<STR_LIT>" , worker_pid ) <EOL> try : <EOL> worker . tmp . close ( ) <EOL> self . cfg . worker_exit ( self , worker ) <EOL> except : <EOL> pass <EOL> def spawn_workers ( self ) : <EOL> """<STR_LIT>""" <EOL> for i in range ( self . num_workers - len ( self . WORKERS . keys ( ) ) ) : <EOL> self . spawn_worker ( ) <EOL> time . sleep ( <NUM_LIT:0.1> * random . random ( ) ) <EOL> def kill_workers ( self , sig ) : <EOL> """<STR_LIT>""" <EOL> worker_pids = list ( self . WORKERS . keys ( ) ) <EOL> for pid in worker_pids : <EOL> self . kill_worker ( pid , sig ) <EOL> def kill_worker ( self , pid , sig ) : <EOL> """<STR_LIT>""" <EOL> try : <EOL> os . kill ( pid , sig ) <EOL> except OSError as e : <EOL> if e . errno == errno . ESRCH : <EOL> try : <EOL> worker = self . WORKERS . pop ( pid ) <EOL> worker . tmp . close ( ) <EOL> self . cfg . worker_exit ( self , worker ) <EOL> return <EOL> except ( KeyError , OSError ) : <EOL> return <EOL> raise </s>
