#!/usr/bin/env python # -*- coding: utf-8 -*- import os import time import optparse from rq import use_redis, Queue, Worker from rq.utils import gettermsize, make_colorizer red = make_colorizer('darkred') green = make_colorizer('darkgreen') yellow = make_colorizer('darkyellow') def pad(s, pad_to_length): """Pads the given string to the given length.""" return ('%-' + '%ds' % pad_to_length) % (s,) def get_scale(x): """Finds the lowest scale where x <= scale.""" scales = [20, 50, 100, 200, 400, 600, 800, 1000] for scale in scales: if x <= scale: return scale return x def state_symbol(state): symbols = { 'busy': red(u'\u25CF'), 'idle': green(u'\u25CB'), } try: return symbols[state] except KeyError: return state def parse_args(): parser = optparse.OptionParser() parser.add_option('-q', '--queues', dest='subcmd', action='store_const', const='queues', help='Shows stats for queues.') parser.add_option('-w', '--workers', dest='subcmd', action='store_const', const='workers', help='Shows stats for workers.') parser.add_option('-n', '--interval', dest='interval', type='float', help='The interval between polls, in seconds. Does not poll if 0.') parser.add_option('-r', '--raw', dest='raw', action='store_true', default=False, help='Print only the raw numbers, no bar charts.') parser.add_option('-Q', '--by-queue', dest='by_queue', default=False, action='store_true', help='Shows workers by queue.') opts, args = parser.parse_args() return (opts, args, parser) def show_queues(opts, args, parser): while True: if len(args): qs = map(Queue, args) else: qs = Queue.all() num_jobs = 0 termwidth, _ = gettermsize() chartwidth = min(20, termwidth - 20) max_count = 0 counts = dict() for q in qs: count = q.count counts[q] = count max_count = max(max_count, count) scale = get_scale(max_count) ratio = chartwidth * 1.0 / scale if opts.interval: os.system('clear') for q in qs: count = counts[q] if not opts.raw: chart = green('|' + '█' * int(ratio * count)) line = '%-12s %s %d' % (q.name, chart, count) else: line = '%-12s %d' % (q.name, count) print(line) num_jobs += count print('%d queues, %d jobs total' % (len(qs), num_jobs)) if opts.interval: time.sleep(opts.interval) else: break def show_workers(opts, args, parser): while True: qs = Queue.all() ws = Worker.all() if opts.interval: os.system('clear') queues = {qname: [] for qname in qs} for w in ws: for q in w.queues: if not q in queues: queues[q] = [] queues[q].append(w) if opts.by_queue: max_qname = max(map(lambda q: len(q.name), queues.keys())) for q in queues: if queues[q]: queues_str = ", ".join(sorted(map(lambda w: '%s (%s)' % (w.name, state_symbol(w.state)), queues[q]))) else: queues_str = '–' print '%s %s' % (pad(q.name + ':', max_qname + 1), queues_str) else: for w in ws: print '%s %s: %s' % (w.name, state_symbol(w.state), ', '.join(w.queue_names())) print '%d workers, %d queues' % (len(ws), len(queues)) if opts.interval: time.sleep(opts.interval) else: break def main(): opts, args, parser = parse_args() if not opts.subcmd: parser.error('Specify either --queues or --workers.') use_redis() if opts.subcmd == 'workers': show_workers(opts, args, parser) elif opts.subcmd == 'queues': show_queues(opts, args, parser) if __name__ == '__main__': main()