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
File: __init__.py Project: zc/sqs
def sequential(args=None):
    if args is None:
        args = sys.argv[1:]

    [ini] = args

    parser = ConfigParser.RawConfigParser()
    with open(ini) as fp:
        parser.readfp(fp)

    container = dict(parser.items('container'))
    name = container.pop('queue')
    region = container.pop('region', 'us-east-1')
    worker = container.pop('worker')
    ZConfig.configureLoggers(container.pop('loggers'))

    if container:
        print("Unexpected container options", container)

    if parser.has_section('worker'):
        worker_options = dict(parser.items('worker'))
    else:
        worker_options = {}

    module, expr = worker.split(':', 1)
    module = __import__(module, {}, {}, ['*'])
    worker = eval(expr, module.__dict__)(worker_options)

    connection = boto.sqs.connect_to_region(region)
    queue = connection.get_queue(name)

    while 1:
        rs = queue.get_messages(wait_time_seconds=20)
        if len(rs):
            message = rs[0]
            data = message.get_body()
            try:
                args, kw = json.loads(data)
                worker(*args, **kw)
            except TransientError:
                continue
            except Exception:
                logger.exception("Handling a message")
                message_logger.info(data)

            queue.delete_message(message)
Example #3
0
def main(args=None):
    """%prog [options] worker_addresses

    Run a resume-based load balancer on the give addresses.
    """
    if args is None:
        args = sys.argv[1:]

    import optparse

    parser = optparse.OptionParser(main.__doc__)
    parser.add_option("-a", "--address", default=":0", help="Address to listed on for web requests")
    parser.add_option(
        "-l", "--access-log", default="-", help="Access-log path.\n\n" "Use - (default) for standard output.\n"
    )
    parser.add_option("-b", "--backlog", type="int", help="Server backlog setting.")
    parser.add_option(
        "-m", "--max-connections", type="int", help="Maximum number of simultanious accepted connections."
    )
    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.",
    )
    parser.add_option(
        "-r",
        "--request-classifier",
        default="zc.resumelb.lb:host_classifier",
        help="Request classification function (module:expr)",
    )
    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(
        "-v", "--variance", type="float", default=4.0, help="Maximum ration of a worker backlog to the mean backlog"
    )
    parser.add_option(
        "--backlog-history", type="int", default=9, help="Rough numner of requests to average worker backlogs over"
    )

    parser.add_option(
        "--unskilled-score", type="float", default=1.0, help="Score (requests/second) to assign to new workers."
    )

    options, args = parser.parse_args(args)
    if not args:
        print "Error: must supply one or more worker addresses."
        parser.parse_args(["-h"])

    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())

    addrs = map(parse_addr, args)
    wsgi_addr = parse_addr(options.address)

    lb = LB(
        addrs,
        host_classifier,
        variance=options.variance,
        backlog_history=options.backlog_history,
        unskilled_score=options.unskilled_score,
    )

    # 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"

    accesslog = options.access_log
    if isinstance(accesslog, str):
        accesslog = sys.stdout if accesslog == "-" else open(accesslog, "a")

    gevent.pywsgi.WSGIServer(wsgi_addr, lb.handle_wsgi, backlog=options.backlog, spawn=spawn, log=accesslog)

    gevent.pywsgi.WSGIServer(wsgi_addr, lb.handle_wsgi).serve_forever()
Example #4
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
Example #5
0
def main(args=None):
    """%prog [options] worker_addresses

    Run a resume-based load balancer on the give addresses.
    """
    if args is None:
        args = sys.argv[1:]

    import optparse
    parser = optparse.OptionParser(main.__doc__)
    parser.add_option(
        '-a', '--address', default=':0',
        help="Address to listed on for web requests"
        )
    parser.add_option(
        '-l', '--access-log', default='-',
        help='Access-log path.\n\n'
        'Use - (default) for standard output.\n'
        )
    parser.add_option(
        '-b', '--backlog', type='int',
        help="Server backlog setting.")
    parser.add_option(
        '-m', '--max-connections', type='int',
        help="Maximum number of simultanious accepted connections.")
    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."
        )
    parser.add_option(
        '-r', '--request-classifier', default='zc.resumelb.lb:host_classifier',
        help="Request classification function (module:expr)"
        )
    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(
        '-v', '--variance', type='float', default=4.0,
        help="Maximum ration of a worker backlog to the mean backlog"
        )
    parser.add_option(
        '--backlog-history', type='int', default=9,
        help="Rough numner of requests to average worker backlogs over"
        )

    parser.add_option(
        '--unskilled-score', type='float', default=1.0,
        help="Score (requests/second) to assign to new workers."
        )

    options, args = parser.parse_args(args)
    if not args:
        print 'Error: must supply one or more worker addresses.'
        parser.parse_args(['-h'])

    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())

    addrs = map(parse_addr, args)
    wsgi_addr = parse_addr(options.address)

    lb = LB(addrs, host_classifier,
            variance=options.variance,
            backlog_history=options.backlog_history,
            unskilled_score=options.unskilled_score)

    # 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'

    accesslog = options.access_log
    if isinstance(accesslog, str):
        accesslog = sys.stdout if accesslog == '-' else open(accesslog, 'a')

    gevent.pywsgi.WSGIServer(
        wsgi_addr, lb.handle_wsgi, backlog = options.backlog,
        spawn = spawn, log = accesslog)

    gevent.pywsgi.WSGIServer(wsgi_addr, lb.handle_wsgi).serve_forever()