Example #1
0
def worker(app, global_conf, zookeeper, path, loggers=None, address=':0',
           threads=None, backdoor=False, description=None, version=None,
           run=True, **kw):
    """Paste deploy server runner
    """
    if loggers:
        if re.match(r'\d+$', loggers):
            logging.basicConfig(level=int(loggers))
        elif loggers in ('CRITICAL', 'ERROR', 'WARNING', 'INFO', 'DEBUG'):
            logging.basicConfig(level=getattr(logging, loggers))
        else:
            import ZConfig
            ZConfig.configureLoggers(loggers)

    zk = zc.zk.ZooKeeper(zookeeper)
    address = zc.parse_addr.parse_addr(address)
    from zc.resumelb.worker import Worker

    worker = Worker(app, address, threads=threads and int(threads),
                    **kw)

    # Set up notification of settings changes.
    settings = zk.properties(path)
    watcher = gevent.get_hub().loop.async()
    watcher.start(lambda : worker.update_settings(settings))
    settings(lambda _: watcher.send())

    registration_data = {}
    if backdoor == 'true':
        from gevent import backdoor
        bd = backdoor.BackdoorServer(('127.0.0.1', 0), locals())
        bd.start()
        registration_data['backdoor'] = '127.0.0.1:%s' % bd.server_port
        worker.__bd = bd

    if description:
        registration_data['description'] = description

    if version:
        registration_data['version'] = version

    zk.register_server(path+'/providers', worker.addr, **registration_data)
    worker.zk = zk
    worker.__zksettings = settings

    def shutdown():
        zk.close()
        worker.shutdown()

    gevent.signal(signal.SIGTERM, shutdown)

    if run:
        try:
            worker.server.serve_forever()
        finally:
            logging.getLogger(__name__+'.worker').info('exiting')
            zk.close()
    else:
        gevent.sleep(.01)
        return worker
Example #2
0
def lbmain(args=None, run=True):
    """%prog [options] zookeeper_connection path

    Run a resume-based load balancer on addr.
    """
    if args is None:
        args = sys.argv[1:]
    elif isinstance(args, str):
        args = args.split()
        run = False
    import optparse
    parser = optparse.OptionParser(lbmain.__doc__)
    parser.add_option(
        '-a', '--address', default=':0',
        help="Address to listed on for web requests"
        )
    parser.add_option(
        '-b', '--backlog', type='int',
        help="Server backlog setting.")
    parser.add_option(
        '-d', '--backdoor', action='store_true',
        help="Run a backdoor server. Use with caution!")
    parser.add_option(
        '-e', '--disconnect-message',
        help="Path to error page to use when a request is lost due to "
        "worker disconnection"
        )
    parser.add_option(
        '-L', '--logger-configuration',
        help=
        "Read logger configuration from the given configuration file path.\n"
        "\n"
        "The configuration file must be in ZConfig logger configuration syntax."
        "\n"
        "Alternatively, you can give a Python logger level name or number."
        )
    parser.add_option('-l', '--access-logger', help='Access-log logger name.')
    parser.add_option(
        '-m', '--max-connections', type='int',
        help="Maximum number of simultanious accepted connections.")
    parser.add_option(
        '-r', '--request-classifier', default='zc.resumelb.lb:host_classifier',
        help="Request classification function (module:expr)"
        )
    parser.add_option(
        '-s', '--status-server',
        help=("Run a status server for getting pool information. "
              "The argument is a unix-domain socket path to listen on."))
    parser.add_option(
        '-t', '--socket-timeout', type='float', default=99.,
        help=('HTTP socket timeout.'))
    parser.add_option(
        '-v', '--single-version', action='store_true',
        help=('Only use a single worker version.'))

    try:
        options, args = parser.parse_args(args)
        if len(args) != 2:
            print 'Error: must supply a zookeeper connection string and path.'
            parser.parse_args(['-h'])
        zookeeper, path = args
    except SystemExit:
        if run:
            raise
        else:
            return

    if options.logger_configuration:
        logger_config = options.logger_configuration
        if re.match(r'\d+$', logger_config):
            logging.basicConfig(level=int(logger_config))
        elif logger_config in ('CRITICAL', 'ERROR', 'WARNING', 'INFO', 'DEBUG'):
            logging.basicConfig(level=getattr(logging, logger_config))
        else:
            import ZConfig
            with open(logger_config) as f:
                ZConfig.configureLoggers(f.read())

    zk = zc.zk.ZooKeeper(zookeeper)
    addrs = zk.children(path+'/workers/providers')
    rcmod, rcexpr = options.request_classifier.split(':')
    __import__(rcmod)
    rcmod = sys.modules[rcmod]
    request_classifier = eval(rcexpr, rcmod.__dict__)

    disconnect_message = options.disconnect_message
    if disconnect_message:
        with open(disconnect_message) as f:
            disconnect_message = f.read()
    else:
        disconnect_message = zc.resumelb.lb.default_disconnect_message

    from zc.resumelb.lb import LB
    lb = LB(map(zc.parse_addr.parse_addr, ()),
            request_classifier, disconnect_message,
            single_version=options.single_version)


    to_send = [[]]
    # Set up notification of address changes.
    awatcher = gevent.get_hub().loop.async()
    @awatcher.start
    def _():
        lb.set_worker_addrs(to_send[0])

    if options.single_version:
        @addrs
        def get_addrs(a):
            to_send[0] = dict(
                (zc.parse_addr.parse_addr(addr),
                 zk.get_properties(
                     path+'/workers/providers/'+addr).get('version')
                 )
                for addr in addrs)
            awatcher.send()
    else:
        @addrs
        def get_addrs(a):
            to_send[0] = map(zc.parse_addr.parse_addr, addrs)
            awatcher.send()

    # Set up notification of address changes.
    settings = zk.properties(path)
    swatcher = gevent.get_hub().loop.async()
    swatcher.start(lambda : lb.update_settings(settings))
    settings(lambda a: swatcher.send())

    lb.zk = zk
    lb.__zk = addrs, settings

    # Now, start a wsgi server
    addr = zc.parse_addr.parse_addr(options.address)
    if options.max_connections:
        spawn= gevent.pool.Pool(options.max_connections)
    else:
        spawn = 'default'

    if options.access_logger:
        accesslog = AccessLog(options.access_logger)
    else:
        accesslog = None

    server = WSGIServer(
        addr, lb.handle_wsgi, backlog=options.backlog,
        spawn=spawn, log=accesslog, socket_timeout=options.socket_timeout)
    server.start()

    registration_data = {}
    if options.backdoor:
        from gevent import backdoor
        bd = backdoor.BackdoorServer(('127.0.0.1', 0), locals())
        bd.start()
        registration_data['backdoor'] = '127.0.0.1:%s' % bd.server_port

    status_server = None
    if options.status_server:
        def status(socket, addr):
            pool = lb.pool
            writer = socket.makefile('w')
            writer.write(json.dumps(
                dict(
                    backlog = pool.backlog,
                    mean_backlog = pool.mbacklog,
                    workers = [
                        (worker.__name__,
                         worker.backlog,
                         worker.mbacklog,
                         (int(worker.oldest_time)
                          if worker.oldest_time else None),
                         )
                        for worker in sorted(
                            pool.workers, key=lambda w: w.__name__)
                        ]
                    ))+'\n')
            writer.close()
            socket.close()

        status_server_address = options.status_server
        if os.path.exists(status_server_address):
            os.remove(status_server_address)
        sock = gevent.socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
        sock.bind(status_server_address)
        sock.listen(5)
        status_server = gevent.server.StreamServer(sock, status)
        status_server.start()

    zk.register_server(path+'/providers', (addr[0], server.server_port),
                       **registration_data)

    def shutdown():
        zk.close()
        server.close()
        if status_server is not None:
            status_server.close()
        lb.shutdown()

    gevent.signal(signal.SIGTERM, shutdown)

    if run:
        try:
            server.serve_forever()
        finally:
            logging.getLogger(__name__+'.lbmain').info('exiting')
            zk.close()
    else:
        gevent.sleep(.01)
        return lb, server