Beispiel #1
0
    def _real_init(self, sock, basepath, module, args):
        """Actual initialization function. Broken out for error handling"""

        setproctitle('zygote name=%s version=%s' % (self.name, self._version(),))

        # Create a pipe(2) pair. This will be used so workers can detect when
        # the intermediate zygote exits -- when this happens, a read event will
        # happen on the read_pipe file descriptor, and the child can exit. We do
        # this so that if the intermediate zygote exits unexpectedly for some
        # reason, while it still has children workers running (which is an
        # abnormal situation in and of itself), we aren't left with orphaned
        # worker processes. Note that the write_pipe is normally never written
        # on, we're just using this hack to get a read event on the read pipe.
        self.read_pipe, self.write_pipe = os.pipe()

        self.io_loop = ZygoteIOLoop(log_name='zygote.worker.ioloop')

        os.chdir(basepath)

        # Add basepath to sys.path so that application will be able to
        # load what's required. We do this at zygote initialization
        # to have the correct paths at new code reload.
        site.addsitedir(os.path.realpath(basepath))

        t = __import__(module, [], [], ['initialize', 'get_application'], 0)

        self.sock = sock

        self.get_application = t.get_application

        set_nonblocking(self.control_socket)
        self.io_loop.add_handler(self.control_socket.fileno(), self.handle_control, self.io_loop.READ)

        self.notify_socket = AFUnixSender(self.io_loop)
        self.notify_socket.connect('\0zygote_%d' % self.ppid)

        signal.signal(signal.SIGCHLD, self.reap_child)

        # If there is an initialize function defined then call it.
        if hasattr(t, 'initialize'):
            self.logger.info('initializing zygote')
            t.initialize(*self.args)

        if self.canary:
            notify(self.notify_socket, message.MessageCanaryInit)
            # Initialization is successful. This is not the canary zygote anymore.
            self.canary = False

        self.logger.info('new zygote started')
Beispiel #2
0
    def _real_init(self, sock, basepath, module, args):
        """Actual initialization function. Broken out for error handling"""

        self.version = basepath.split("/")[-1]
        setproctitle("zygote version=%s" % (self.version,))

        # Create a pipe(2) pair. This will be used so workers can detect when
        # the intermediate zygote exits -- when this happens, a read event will
        # happen on the read_pipe file descriptor, and the child can exit. We do
        # this so that if the intermediate zygote exits unexpectedly for some
        # reason, while it still has children workers running (which is an
        # abnormal situation in and of itself), we aren't left with orphaned
        # worker processes. Note that the write_pipe is normally never written
        # on, we're just using this hack to get a read event on the read pipe.
        self.read_pipe, self.write_pipe = os.pipe()

        self.io_loop = ZygoteIOLoop(log_name="zygote.worker.ioloop")

        os.chdir(basepath)
        sys.path.insert(0, basepath)
        t = __import__(module, [], [], ["initialize", "get_application"], 0)

        self.sock = sock

        self.get_application = t.get_application

        set_nonblocking(self.control_socket)
        self.io_loop.add_handler(self.control_socket.fileno(), self.handle_control, self.io_loop.READ)

        self.notify_socket = AFUnixSender(self.io_loop)
        self.notify_socket.connect("\0zygote_%d" % self.ppid)

        signal.signal(signal.SIGCHLD, self.reap_child)

        # If there is an initialize function defined then call it.
        if hasattr(t, "initialize"):
            self.logger.info("initializing zygote")
            t.initialize(*self.args)

        if self.canary:
            notify(self.notify_socket, message.MessageCanaryInit)
            # Initialization is successful. This is not the canary zygote anymore.
            self.canary = False

        self.logger.info("new zygote started")
Beispiel #3
0
def main(opts, extra_args):
    setproctitle('zygote master %s' % (opts.name or opts.module, ))
    zygote_logger = get_logger('zygote', opts.debug)

    if not logging.root.handlers:
        # XXX: WARNING
        #
        # We're disabling the root logger. Tornado's RequestHandler ONLY
        # supports logging uncaught errors to the root logger. This will end
        # poorly for you!
        #
        # We should probably provide a RequestHandler subclass that has
        # _handle_request_exception overridden to do something useful.
        # That might be hard to do without adding a tight version dependency
        # on tornado.
        logging.root.addHandler(NullHandler())

    if opts.debug:
        logging.root.setLevel(logging.DEBUG)
    else:
        logging.root.setLevel(logging.INFO)

    zygote_logger.info('main started')

    # Create the TCP listen socket
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    flags = fcntl.fcntl(sock.fileno(), fcntl.F_GETFD)
    flags |= fcntl.FD_CLOEXEC
    fcntl.fcntl(sock.fileno(), fcntl.F_SETFD, flags)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.setblocking(0)
    sock.bind((opts.interface, opts.port))
    sock.listen(128)

    ssl_options = None
    if opts.cert:
        ssl_options = dict(
            certfile=opts.cert,
            keyfile=opts.key,
            ca_certs=opts.cacerts,
            cert_reqs=ssl.CERT_OPTIONAL if opts.cacerts else ssl.CERT_NONE,
        )
        zygote_logger.info('using SSL with %s', ssl_options)

        sock = ssl.wrap_socket(sock,
                               server_side=True,
                               do_handshake_on_connect=False,
                               **ssl_options)

    master = ZygoteMaster(sock,
                          basepath=opts.basepath,
                          module=opts.module,
                          name=opts.name or opts.module,
                          version=opts.version,
                          num_workers=opts.num_workers,
                          control_port=opts.control_port,
                          control_socket_path=opts.control_socket_path,
                          application_args=extra_args,
                          max_requests=opts.max_requests,
                          zygote_base=opts.zygote_base,
                          ssl_options=ssl_options,
                          debug=opts.debug)
    atexit.register(master.stop)
    master.start()
Beispiel #4
0
    def _initialize_worker(self, time_created):
        # We're the child. We need to close the write_pipe in order for the
        # read_pipe to get an event when the parent's write_pipe closes
        # (otherwise the kernel is too smart and thinks that it's waiting
        # for writes from *this* process' write_pipe).
        os.close(self.write_pipe)

        logger = get_logger('zygote.worker.worker_process')
        logger.debug('new worker started')

        def on_parent_exit(fd, events):
            logger.error('detected that intermediate zygote died, exiting')
            sys.exit(0)

        # create a new i/o loop
        del self.io_loop
        io_loop = ZygoteIOLoop(log_name='zygote.worker.worker_process.ioloop')
        # Install this worker's io_loop as the global io_loop; only applies in
        # this fork. Programs that uses this io_loop instance should NOT use
        # io_loop.start() because start() is invoked by the corresponding
        # zygote worker.
        if tornado.version_info >= (2,1,0):
            io_loop.install()
        else:
            tornado.ioloop.IOLoop._instance = io_loop

        # add the read pipe
        io_loop.add_handler(self.read_pipe, on_parent_exit, io_loop.READ)

        sock = AFUnixSender(io_loop, logger=logger)
        sock.connect('\0zygote_%d' % self.ppid)

        establish_signal_handlers(logger)
        def on_headers(line, remote_ip, headers):
            logger.debug('sending MessageHTTPBegin')
            notify(sock, message.MessageHTTPBegin, "%s %s" % (remote_ip, line))
        def on_close(disconnected=False):
            logger.debug('sending MessageHTTPEnd')
            notify(sock, message.MessageHTTPEnd)

        notify(sock, message.MessageWorkerStart, '%d %d' % (int(time_created * 1e6), os.getppid()))
        setproctitle('zygote-worker name=%s version=%s' % (self.name, self._version(),))
        try:
            # io_loop is passed into get_application for program to add handler
            # or schedule task on the main io_loop.  Program that uses this
            # io_loop instance should NOT use io_loop.start() because start()
            # is invoked by the corresponding zygote worker.
            kwargs = {'io_loop': io_loop}
            logger.debug("Invoking get_application")
            app = self.get_application(*self.args, **kwargs)
        except Exception:
            logger.error("Unable to get application")
            raise
        # TODO: make keep-alive servers work
        logger.debug("Creating HTTPServer")
        http_server = HTTPServer(app,
                io_loop=io_loop,
                no_keep_alive=True,
                close_callback=on_close,
                headers_callback=on_headers,
                ssl_options=self.ssl_options
        )
        if tornado.version_info >= (2,1,0):
            http_server.add_socket(self.sock)
        else:
            http_server._socket = self.sock
            io_loop.add_handler(self.sock.fileno(), http_server._handle_events, io_loop.READ)
        logger.debug("Started ioloop...")
        io_loop.start()
Beispiel #5
0
def main(opts, extra_args):
    setproctitle('zygote master %s' % (opts.module,))
    zygote_logger = get_logger('zygote', opts.debug)
    
    if not logging.root.handlers:
        # XXX: WARNING
        #
        # We're disabling the root logger. Tornado's RequestHandler ONLY
        # supports logging uncaught errors to the root logger. This will end
        # poorly for you!
        #
        # We should probably provide a RequestHandler subclass that has
        # _handle_request_exception overridden to do something useful.
        # That might be hard to do without adding a tight version dependency
        # on tornado.
        logging.root.addHandler(NullHandler())

    if opts.debug:
        logging.root.setLevel(logging.DEBUG)
    else:
        logging.root.setLevel(logging.INFO)

    zygote_logger.info('main started')

    # Create the TCP listen socket
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    flags = fcntl.fcntl(sock.fileno(), fcntl.F_GETFD)
    flags |= fcntl.FD_CLOEXEC
    fcntl.fcntl(sock.fileno(), fcntl.F_SETFD, flags)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.setblocking(0)
    sock.bind((opts.interface, opts.port))
    sock.listen(128)

    ssl_options=None
    if opts.cert:
        ssl_options = dict(
                certfile=opts.cert,
                keyfile=opts.key,
                ca_certs=opts.cacerts,
                cert_reqs=ssl.CERT_OPTIONAL if opts.cacerts else ssl.CERT_NONE,
        )
        zygote_logger.info('using SSL with %s', ssl_options)

        sock = ssl.wrap_socket(sock,
                server_side=True,
                do_handshake_on_connect=False,
                **ssl_options
        )

    master = ZygoteMaster(
        sock,
        basepath=opts.basepath,
        module=opts.module,
        num_workers=opts.num_workers,
        control_port=opts.control_port,
        control_socket_path=opts.control_socket_path,
        application_args=extra_args,
        max_requests=opts.max_requests,
        zygote_base=opts.zygote_base,
        ssl_options=ssl_options,
        debug=opts.debug
    )
    atexit.register(master.stop)
    master.start()