nova-api代码分析(3)

来源:互联网 发布:java xml解析成json 编辑:程序博客网 时间:2024/05/10 16:12

nova-api代码分析,我们继续分析WSGIService的代码。


class WSGIService(object):    """Provides ability to launch API from a 'paste' configuration."""    #WSGIService的初始化方法    def __init__(self, name, loader=None, use_ssl=False, max_url_len=None):        """Initialize, but do not start the WSGI server.        :param name: The name of the WSGI server given to the loader.        :param loader: Loads the WSGI application using the given name.        :returns: None        """        self.name = name        self.manager = self._get_manager()        #初始化WSGI loader实例        self.loader = loader or wsgi.Loader()        #调用load_app方法加载paste配置文件        self.app = self.loader.load_app(name)        #获取主机名        self.host = getattr(CONF, '%s_listen' % name, "0.0.0.0")        #获取端口号        self.port = getattr(CONF, '%s_listen_port' % name, 0)        #获取worker进程数        self.workers = (getattr(CONF, '%s_workers' % name, None) or                        processutils.get_worker_count())        if self.workers and self.workers < 1:            worker_name = '%s_workers' % name            msg = (_("%(worker_name)s value of %(workers)s is invalid, "                     "must be greater than 0") %                   {'worker_name': worker_name,                    'workers': str(self.workers)})            raise exception.InvalidInput(msg)        self.use_ssl = use_ssl        #初始化Server        self.server = wsgi.Server(name,                                  self.app,                                  host=self.host,                                  port=self.port,                                  use_ssl=self.use_ssl,                                  max_url_len=max_url_len)        # Pull back actual port used        self.port = self.server.port        self.backdoor_port = None


wsgi.Server用来初始化WSGI Server

class Server(object):    """Server class to manage a WSGI server, serving a WSGI application."""    #设定默认池大小,初始化为1000    default_pool_size = CONF.wsgi_default_pool_size    def __init__(self, name, app, host='0.0.0.0', port=0, pool_size=None,                       protocol=eventlet.wsgi.HttpProtocol, backlog=128,                       use_ssl=False, max_url_len=None):        """Initialize, but do not start, a WSGI server.        :param name: Pretty name for logging.        :param app: The WSGI application to serve.        :param host: IP address to serve the application.        :param port: Port number to server the application.        :param pool_size: Maximum number of eventlets to spawn concurrently.        :param backlog: Maximum number of queued connections.        :param max_url_len: Maximum length of permitted URLs.        :returns: None        :raises: nova.exception.InvalidInput        """        # Allow operators to customize http requests max header line size.        eventlet.wsgi.MAX_HEADER_LINE = CONF.max_header_line        self.name = name        self.app = app        self._server = None        self._protocol = protocol        self.pool_size = pool_size or self.default_pool_size        #定义eventlet绿色线程池,默认大小1000线程        self._pool = eventlet.GreenPool(self.pool_size)        self._logger = logging.getLogger("nova.%s.wsgi.server" % self.name)        self._wsgi_logger = logging.WritableLogger(self._logger)        self._use_ssl = use_ssl        self._max_url_len = max_url_len        if backlog < 1:            raise exception.InvalidInput(                    reason='The backlog must be more than 1')        bind_addr = (host, port)        # TODO(dims): eventlet's green dns/socket module does not actually        # support IPv6 in getaddrinfo(). We need to get around this in the        # future or monitor upstream for a fix        try:            #返回socket连接信息信息字典<tt class="docutils literal"><span class="pre">(family,</span> <span class="pre">socktype,</span> <span class="pre">proto,</span> <span class="pre">canonname,</span> <span class="pre">sockaddr)</span></tt>            info = socket.getaddrinfo(bind_addr[0],                                      bind_addr[1],                                      socket.AF_UNSPEC,                                      socket.SOCK_STREAM)[0]            family = info[0]            bind_addr = info[-1]        except Exception:            family = socket.AF_INET        try:            #打开协程eventlet.listen监听端口            self._socket = eventlet.listen(bind_addr, family, backlog=backlog)        except EnvironmentError:            LOG.error(_("Could not bind to %(host)s:%(port)s"),                      {'host': host, 'port': port})            raise        #获取主机和端口信息        (self.host, self.port) = self._socket.getsockname()[0:2]        LOG.info(_("%(name)s listening on %(host)s:%(port)s") % self.__dict__)

到此server = service.WSGIService(api, use_ssl=should_use_ssl)启动WSGIService已经完成,

下面继续分析launcher.launch_service(server, workers=server.workers or 1)

    def launch_service(self, service, workers=1):        #service wrapper包装类        wrap = ServiceWrapper(service, workers)        LOG.info(_LI('Starting %d workers'), wrap.workers)        while self.running and len(wrap.children) < wrap.workers:            #启动子进程            self._start_child(wrap)

class ServiceWrapper(object):    def __init__(self, service, workers):        #WSGI Service        self.service = service        #workers工作进程        self.workers = workers        #子进程        self.children = set()        #记录fork进程的时间        self.forktimes = []

    def _start_child(self, wrap):        if len(wrap.forktimes) > wrap.workers:            # Limit ourselves to one process a second (over the period of            # number of workers * 1 second). This will allow workers to            # start up quickly but ensure we don't fork off children that            # die instantly too quickly.            if time.time() - wrap.forktimes[0] < wrap.workers:                LOG.info(_LI('Forking too fast, sleeping'))                time.sleep(1)            wrap.forktimes.pop(0)        #记录fork进程时间        wrap.forktimes.append(time.time())        #fork进程        pid = os.fork()        #pid等于0进入到子进程里        if pid == 0:                        launcher = self._child_process(wrap.service)            while True:                self._child_process_handle_signal()                status, signo = self._child_wait_for_exit_or_signal(launcher)                if not _is_sighup_and_daemon(signo):                    break                launcher.restart()            os._exit(status)        LOG.info(_LI('Started child %d'), pid)        wrap.children.add(pid)        self.children[pid] = wrap        return pid

执行launcher.wait()方法:

    def wait(self):        """Loop waiting on children to die and respawning as necessary."""        LOG.debug('Full set of CONF:')        CONF.log_opt_values(LOG, std_logging.DEBUG)        try:            while True:                self.handle_signal()                self._respawn_children()                if self.sigcaught:                    signame = _signo_to_signame(self.sigcaught)                    LOG.info(_LI('Caught %s, stopping children'), signame)                if not _is_sighup_and_daemon(self.sigcaught):                    break                for pid in self.children:                    os.kill(pid, signal.SIGHUP)                self.running = True                self.sigcaught = None        except eventlet.greenlet.GreenletExit:            LOG.info(_LI("Wait called after thread killed.  Cleaning up."))        for pid in self.children:            try:                os.kill(pid, signal.SIGTERM)            except OSError as exc:                if exc.errno != errno.ESRCH:                    raise        # Wait for children to die        if self.children:            LOG.info(_LI('Waiting on %d children to exit'), len(self.children))            while self.children:                self._wait_child()



0 0
原创粉丝点击