diff --git a/rq/scripts/rq.py b/rq/scripts/rq_cli.py similarity index 94% rename from rq/scripts/rq.py rename to rq/scripts/rq_cli.py index 328ea91..a9470af 100755 --- a/rq/scripts/rq.py +++ b/rq/scripts/rq_cli.py @@ -11,18 +11,20 @@ import redis from rq import get_failed_queue, Queue, use_connection from rq.exceptions import InvalidJobOperationError +from rqinfo import info + @click.group() @click.option('--url', '-u', envvar='URL', help='URL describing Redis connection details.') -def rq(url): +def main(url): if url is None: url = "redis://localhost:6379/0" redis_conn = redis.from_url(url) use_connection(redis_conn) -@rq.command() +@main.command() @click.argument('queues', nargs=-1) def empty(queues): """[QUEUES]: queues to empty, default: failed queue @@ -43,7 +45,7 @@ def empty(queues): click.echo('{} jobs removed from {} queue'.format(num_jobs, queue.name)) -@rq.command() +@main.command() def requeue(): """Requeue all failed jobs in failed queue""" failed_queue = get_failed_queue() @@ -59,3 +61,6 @@ def requeue(): click.secho('Requeue failed: {}'.format( requeue_failed_num), fg='red') + + +main.add_command(info) diff --git a/rq/scripts/rqinfo.py b/rq/scripts/rqinfo.py index 48d318a..d9a51a2 100755 --- a/rq/scripts/rqinfo.py +++ b/rq/scripts/rqinfo.py @@ -3,20 +3,18 @@ from __future__ import (absolute_import, division, print_function, unicode_literals) -import argparse -import os import sys import time +import click +from functools import partial from redis.exceptions import ConnectionError -from rq import get_failed_queue, Queue, Worker -from rq.scripts import (add_standard_arguments, read_config_file, - setup_default_arguments, setup_redis) -from rq.utils import gettermsize, make_colorizer +from rq import Queue, Worker -red = make_colorizer('darkred') -green = make_colorizer('darkgreen') -yellow = make_colorizer('darkyellow') + +red = partial(click.style, fg='red') +green = partial(click.style, fg='green') +yellow = partial(click.style, fg='yellow') def pad(s, pad_to_length): @@ -44,14 +42,14 @@ def state_symbol(state): return state -def show_queues(args): - if len(args.queues): - qs = list(map(Queue, args.queues)) +def show_queues(queues, raw, by_queue): + if len(queues): + qs = list(map(Queue, queues)) else: qs = Queue.all() num_jobs = 0 - termwidth, _ = gettermsize() + termwidth, _ = click.get_terminal_size() chartwidth = min(20, termwidth - 20) max_count = 0 @@ -65,23 +63,23 @@ def show_queues(args): for q in qs: count = counts[q] - if not args.raw: + if not raw: chart = green('|' + '█' * int(ratio * count)) line = '%-12s %s %d' % (q.name, chart, count) else: line = 'queue %s %d' % (q.name, count) - print(line) + click.echo(line) num_jobs += count - # Print summary when not in raw mode - if not args.raw: - print('%d queues, %d jobs total' % (len(qs), num_jobs)) + # print summary when not in raw mode + if not raw: + click.echo('%d queues, %d jobs total' % (len(qs), num_jobs)) -def show_workers(args): - if len(args.queues): - qs = list(map(Queue, args.queues)) +def show_workers(queues, raw, by_queue): + if len(queues): + qs = list(map(Queue, queues)) def any_matching_queue(worker): def queue_matches(q): @@ -99,13 +97,13 @@ def show_workers(args): ws = Worker.all() filter_queues = lambda x: x - if not args.by_queue: + if not by_queue: for w in ws: worker_queues = filter_queues(w.queue_names()) - if not args.raw: - print('%s %s: %s' % (w.name, state_symbol(w.get_state()), ', '.join(worker_queues))) + if not raw: + click.echo('%s %s: %s' % (w.name, state_symbol(w.get_state()), ', '.join(worker_queues))) else: - print('worker %s %s %s' % (w.name, w.get_state(), ','.join(worker_queues))) + click.echo('worker %s %s %s' % (w.name, w.get_state(), ','.join(worker_queues))) else: # Create reverse lookup table queues = dict([(q, []) for q in qs]) @@ -121,78 +119,60 @@ def show_workers(args): queues_str = ", ".join(sorted(map(lambda w: '%s (%s)' % (w.name, state_symbol(w.get_state())), queues[q]))) # noqa else: queues_str = '–' - print('%s %s' % (pad(q.name + ':', max_qname + 1), queues_str)) + click.echo('%s %s' % (pad(q.name + ':', max_qname + 1), queues_str)) - if not args.raw: - print('%d workers, %d queues' % (len(ws), len(qs))) + if not raw: + click.echo('%d workers, %d queues' % (len(ws), len(qs))) -def show_both(args): - show_queues(args) - if not args.raw: - print('') - show_workers(args) - if not args.raw: - print('') +def show_both(queues, raw, by_queue): + show_queues(queues, raw, by_queue) + if not raw: + click.echo('') + show_workers(queues, raw, by_queue) + if not raw: + click.echo('') import datetime - print('Updated: %s' % datetime.datetime.now()) - + click.echo('Updated: %s' % datetime.datetime.now()) -def parse_args(): - parser = argparse.ArgumentParser(description='RQ command-line monitor.') - add_standard_arguments(parser) - parser.add_argument('--path', '-P', default='.', help='Specify the import path.') - parser.add_argument('--interval', '-i', metavar='N', type=float, default=2.5, help='Updates stats every N seconds (default: don\'t poll)') # noqa - parser.add_argument('--raw', '-r', action='store_true', default=False, help='Print only the raw numbers, no bar charts') # noqa - parser.add_argument('--only-queues', '-Q', dest='only_queues', default=False, action='store_true', help='Show only queue info') # noqa - parser.add_argument('--only-workers', '-W', dest='only_workers', default=False, action='store_true', help='Show only worker info') # noqa - parser.add_argument('--by-queue', '-R', dest='by_queue', default=False, action='store_true', help='Shows workers by queue') # noqa - parser.add_argument('--empty-failed-queue', '-X', dest='empty_failed_queue', default=False, action='store_true', help='Empties the failed queue, then quits') # noqa - parser.add_argument('queues', nargs='*', help='The queues to poll') - return parser.parse_args() - -def interval(val, func, args): +def refresh(val, func, *args): while True: - if val and sys.stdout.isatty(): - os.system('clear') - func(args) - if val and sys.stdout.isatty(): + if val: + click.clear() + func(*args) + if val: time.sleep(val) else: break -def main(): - args = parse_args() - - if args.path: - sys.path = args.path.split(':') + sys.path +@click.command() +@click.option('--path', '-P', default='.', help='Specify the import path.') +@click.option('--interval', '-i', default=2.5, help='Updates stats every N seconds (default: don\'t poll)') # noqa +@click.option('--raw', '-r', is_flag=True, help='Print only the raw numbers, no bar charts') # noqa +@click.option('--only-queues', '-Q', is_flag=True, help='Show only queue info') # noqa +@click.option('--only-workers', '-W', is_flag=True, help='Show only worker info') # noqa +@click.option('--by-queue', '-R', is_flag=True, help='Shows workers by queue') # noqa +@click.argument('queues', nargs=-1) +def info(path, interval, raw, only_queues, only_workers, by_queue, queues): + """RQ command-line monitor.""" - settings = {} - if args.config: - settings = read_config_file(args.config) - - setup_default_arguments(args, settings) - - setup_redis(args) + if path: + sys.path = path.split(':') + sys.path try: - if args.empty_failed_queue: - num_jobs = get_failed_queue().empty() - print('{} jobs removed from failed queue'.format(num_jobs)) + if only_queues: + func = show_queues + elif only_workers: + func = show_workers else: - if args.only_queues: - func = show_queues - elif args.only_workers: - func = show_workers - else: - func = show_both + func = show_both - interval(args.interval, func, args) + refresh(interval, func, queues, raw, by_queue) except ConnectionError as e: - print(e) + click.echo(e) sys.exit(1) except KeyboardInterrupt: - print() + click.echo() sys.exit(0) diff --git a/setup.py b/setup.py index 5ac56b8..3aeddc2 100644 --- a/setup.py +++ b/setup.py @@ -43,7 +43,7 @@ setup( install_requires=get_dependencies(), entry_points='''\ [console_scripts] - rq = rq.scripts.rq:rq + rq = rq.scripts.rq_cli:main rqworker = rq.scripts.rqworker:main rqinfo = rq.scripts.rqinfo:main ''',