From 79393dee16f83e02dacbdcd008631e69f92ed0bc Mon Sep 17 00:00:00 2001 From: Ilan Date: Sun, 9 Aug 2015 19:29:24 +0200 Subject: [PATCH 1/6] adds --info summary to monitor command --- django_q/management/commands/qmonitor.py | 13 ++++- django_q/monitor.py | 64 ++++++++++++++++++++---- django_q/tests/test_commands.py | 3 +- django_q/tests/test_monitor.py | 12 ++++- 4 files changed, 78 insertions(+), 14 deletions(-) diff --git a/django_q/management/commands/qmonitor.py b/django_q/management/commands/qmonitor.py index 570a3ba9..efab4571 100644 --- a/django_q/management/commands/qmonitor.py +++ b/django_q/management/commands/qmonitor.py @@ -4,7 +4,7 @@ from django.core.management.base import BaseCommand from django.utils.translation import ugettext as _ -from django_q.monitor import monitor +from django_q.monitor import monitor, info class Command(BaseCommand): @@ -17,7 +17,16 @@ class Command(BaseCommand): dest='run_once', default=False, help='Run once and then stop.'), + make_option('-i', '--info', + action='store_true', + dest='info', + default=False, + help='Lists general information over all clusters. ') ) def handle(self, *args, **options): - monitor(run_once=options.get('run_once', False)) + if options.get('info', False): + info() + else: + monitor(run_once=options.get('run_once', False)) + diff --git a/django_q/monitor.py b/django_q/monitor.py index 3b001c1f..fa88f7dd 100644 --- a/django_q/monitor.py +++ b/django_q/monitor.py @@ -10,17 +10,12 @@ # local import signing from django_q.conf import Conf, redis_client, logger +from django_q import models -def monitor(run_once=False): +def monitor(run_once=False, r=redis_client): term = Terminal() - r = redis_client - try: - redis_client.ping() - except Exception as e: - print(term.red('Can not connect to Redis server.')) - logger.exception(e) - raise e + ping_redis(r) with term.fullscreen(), term.hidden_cursor(), term.cbreak(): val = None start_width = int(term.width / 8) @@ -88,7 +83,6 @@ def monitor(run_once=False): class Status(object): - """Cluster status base class.""" def __init__(self, pid): @@ -107,7 +101,6 @@ def __init__(self, pid): class Stat(Status): - """Status object for Cluster monitoring.""" def __init__(self, sentinel): @@ -194,3 +187,54 @@ def __getstate__(self): state = dict(self.__dict__) del state['r'] return state + + +def info(r=redis_client): + term = Terminal() + ping_redis(r) + stat = Stat.get_all(r) + clusters = len(stat) + workers = 0 + reincarnations = 0 + for cluster in stat: + workers += len(cluster.workers) + reincarnations += cluster.reincarnations + term.clear_eos() + col_width = int(term.width / 6) + print(term.black_on_green(term.center(_('-- {} clusters summary --').format(Conf.PREFIX)))) + print(term.cyan(_('Clusters')) + + term.move_x(1 * col_width) + + term.white(str(clusters)) + + term.move_x(2 * col_width) + + term.cyan(_('Workers')) + + term.move_x(3 * col_width) + + term.white(str(workers)) + + term.move_x(4 * col_width) + + term.cyan(_('Restarts')) + + term.move_x(5 * col_width) + + term.white(str(reincarnations)) + ) + print(term.cyan(_('Queued')) + + term.move_x(1 * col_width) + + term.white(str(r.llen(Conf.Q_LIST))) + + term.move_x(2 * col_width) + + term.cyan(_('Successes')) + + term.move_x(3 * col_width) + + term.white(str(models.Success.objects.count())) + + term.move_x(4 * col_width) + + term.cyan(_('Failures')) + + term.move_x(5 * col_width) + + term.white(str(models.Failure.objects.count())) + ) + return True + + +def ping_redis(r): + try: + r.ping() + except Exception as e: + term = Terminal() + print(term.red('Can not connect to Redis server.')) + logger.exception(e) + raise e + diff --git a/django_q/tests/test_commands.py b/django_q/tests/test_commands.py index 3fc1ddef..7dc94988 100644 --- a/django_q/tests/test_commands.py +++ b/django_q/tests/test_commands.py @@ -6,6 +6,7 @@ def test_qcluster(): call_command('qcluster', run_once=True) - +@pytest.mark.django_db def test_qmonitor(): call_command('qmonitor', run_once=True) + call_command('qmonitor', info=True) diff --git a/django_q/tests/test_monitor.py b/django_q/tests/test_monitor.py index 90ced366..673ba8aa 100644 --- a/django_q/tests/test_monitor.py +++ b/django_q/tests/test_monitor.py @@ -1,5 +1,8 @@ +import pytest +import redis + from django_q.cluster import Cluster -from django_q.monitor import monitor, Stat +from django_q.monitor import monitor, Stat, info, ping_redis def test_monitor(): @@ -17,3 +20,10 @@ def test_monitor(): assert stat.empty_queues() is True break assert found_c is True + + +@pytest.mark.django_db +def test_ping_redis(): + r = redis.StrictRedis(port=6388) + with pytest.raises(Exception): + ping_redis(r) From 63030aa9d11bc8a7d3d8d24d6ee365a890a9e133 Mon Sep 17 00:00:00 2001 From: Ilan Date: Mon, 10 Aug 2015 13:18:50 +0200 Subject: [PATCH 2/6] Tests schedule creation via model --- django_q/tests/test_scheduler.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/django_q/tests/test_scheduler.py b/django_q/tests/test_scheduler.py index 9214d463..074ed848 100644 --- a/django_q/tests/test_scheduler.py +++ b/django_q/tests/test_scheduler.py @@ -90,6 +90,12 @@ def test_scheduler(r): assert schedule is not None assert schedule.last_run() is None scheduler(list_key=list_key) + # via model + Schedule.objects.create(func='django_q.tests.tasks.word_multiply', + args='2', + kwargs='word="django"', + schedule_type=Schedule.DAILY + ) scheduler(list_key=list_key) # ONCE schedule should be deleted assert Schedule.objects.filter(pk=once_schedule.pk).exists() is False From e86308b434f7aa667d9eac9f9941c80d041d7221 Mon Sep 17 00:00:00 2001 From: Ilan Date: Mon, 10 Aug 2015 13:20:17 +0200 Subject: [PATCH 3/6] adds `qinfo` management command It seems more practical to give this its own command instead of `qmonitor --info` --- django_q/management/commands/qinfo.py | 12 ++++++++++++ django_q/management/commands/qmonitor.py | 14 ++------------ django_q/monitor.py | 2 +- django_q/tests/test_commands.py | 7 ++++++- django_q/tests/test_monitor.py | 2 +- 5 files changed, 22 insertions(+), 15 deletions(-) create mode 100644 django_q/management/commands/qinfo.py diff --git a/django_q/management/commands/qinfo.py b/django_q/management/commands/qinfo.py new file mode 100644 index 00000000..d66772a5 --- /dev/null +++ b/django_q/management/commands/qinfo.py @@ -0,0 +1,12 @@ +from django.core.management.base import BaseCommand +from django.utils.translation import ugettext as _ + +from django_q.monitor import info + + +class Command(BaseCommand): + # Translators: help text for qinfo management command + help = _('General information over all clusters.') + + def handle(self, *args, **options): + info() diff --git a/django_q/management/commands/qmonitor.py b/django_q/management/commands/qmonitor.py index efab4571..bef4bd1e 100644 --- a/django_q/management/commands/qmonitor.py +++ b/django_q/management/commands/qmonitor.py @@ -1,10 +1,9 @@ -# Django from optparse import make_option from django.core.management.base import BaseCommand from django.utils.translation import ugettext as _ -from django_q.monitor import monitor, info +from django_q.monitor import monitor class Command(BaseCommand): @@ -17,16 +16,7 @@ class Command(BaseCommand): dest='run_once', default=False, help='Run once and then stop.'), - make_option('-i', '--info', - action='store_true', - dest='info', - default=False, - help='Lists general information over all clusters. ') ) def handle(self, *args, **options): - if options.get('info', False): - info() - else: - monitor(run_once=options.get('run_once', False)) - + monitor(run_once=options.get('run_once', False)) diff --git a/django_q/monitor.py b/django_q/monitor.py index fa88f7dd..f009cf99 100644 --- a/django_q/monitor.py +++ b/django_q/monitor.py @@ -201,7 +201,7 @@ def info(r=redis_client): reincarnations += cluster.reincarnations term.clear_eos() col_width = int(term.width / 6) - print(term.black_on_green(term.center(_('-- {} clusters summary --').format(Conf.PREFIX)))) + print(term.black_on_green(term.center(_('-- {} summary --').format(Conf.PREFIX)))) print(term.cyan(_('Clusters')) + term.move_x(1 * col_width) + term.white(str(clusters)) + diff --git a/django_q/tests/test_commands.py b/django_q/tests/test_commands.py index 7dc94988..84e80a68 100644 --- a/django_q/tests/test_commands.py +++ b/django_q/tests/test_commands.py @@ -6,7 +6,12 @@ def test_qcluster(): call_command('qcluster', run_once=True) + @pytest.mark.django_db def test_qmonitor(): call_command('qmonitor', run_once=True) - call_command('qmonitor', info=True) + + +@pytest.mark.django_db +def test_qinfo(): + call_command('qinfo') diff --git a/django_q/tests/test_monitor.py b/django_q/tests/test_monitor.py index 673ba8aa..797a5a0c 100644 --- a/django_q/tests/test_monitor.py +++ b/django_q/tests/test_monitor.py @@ -2,7 +2,7 @@ import redis from django_q.cluster import Cluster -from django_q.monitor import monitor, Stat, info, ping_redis +from django_q.monitor import monitor, Stat, ping_redis def test_monitor(): From df7f8bbcaf1034d674ea6013b2df91b4ec7873ab Mon Sep 17 00:00:00 2001 From: Ilan Date: Wed, 12 Aug 2015 12:39:14 +0200 Subject: [PATCH 4/6] Adds more stats to the `qinfo` command * Average execution time * Tasks per day/hour/minute/second * Number of schedules --- django_q/monitor.py | 46 +++++++++++++++++++++++++++++++++- django_q/tests/test_monitor.py | 18 ++++++++++++- 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/django_q/monitor.py b/django_q/monitor.py index f009cf99..3cbb23d7 100644 --- a/django_q/monitor.py +++ b/django_q/monitor.py @@ -1,9 +1,12 @@ +from datetime import timedelta import socket # external from blessed import Terminal # django +from django.db import connection +from django.db.models import Sum, F from django.utils import timezone from django.utils.translation import ugettext as _ @@ -193,12 +196,42 @@ def info(r=redis_client): term = Terminal() ping_redis(r) stat = Stat.get_all(r) + # general stats clusters = len(stat) workers = 0 reincarnations = 0 for cluster in stat: workers += len(cluster.workers) reincarnations += cluster.reincarnations + # calculate tasks pm and avg exec time + tasks_per = 0 + per = _('day') + exec_time = 0 + last_tasks = models.Success.objects.filter(stopped__gte=timezone.now() - timedelta(hours=24)) + tasks_per_day = last_tasks.count() + if tasks_per_day > 0: + # average execution time over the last 24 hours + if not connection.vendor == 'sqlite': + exec_time = last_tasks.aggregate(time_taken=Sum(F('stopped') - F('started'))) + exec_time = exec_time['time_taken'].total_seconds() / tasks_per_day + else: + # can't sum timedeltas on sqlite + for t in last_tasks: + exec_time += t.time_taken() + exec_time = exec_time / tasks_per_day + # tasks per second/minute/hour/day in the last 24 hours + if tasks_per_day > 24 * 60 * 60: + tasks_per = tasks_per_day / (24 * 60 * 60) + per = _('second') + elif tasks_per_day > 24 * 60: + tasks_per = tasks_per_day / (24 * 60) + per = _('minute') + elif tasks_per_day > 24: + tasks_per = tasks_per_day / 24 + per = _('hour') + else: + tasks_per = tasks_per_day + # print to terminal term.clear_eos() col_width = int(term.width / 6) print(term.black_on_green(term.center(_('-- {} summary --').format(Conf.PREFIX)))) @@ -226,6 +259,18 @@ def info(r=redis_client): term.move_x(5 * col_width) + term.white(str(models.Failure.objects.count())) ) + print(term.cyan(_('Schedules')) + + term.move_x(1 * col_width) + + term.white(str(models.Schedule.objects.count())) + + term.move_x(2 * col_width) + + term.cyan(_('Tasks/{}'.format(per))) + + term.move_x(3 * col_width) + + term.white('{0:.2f}'.format(tasks_per)) + + term.move_x(4 * col_width) + + term.cyan(_('Avg time')) + + term.move_x(5 * col_width) + + term.white('{0:.4f}'.format(exec_time)) + ) return True @@ -237,4 +282,3 @@ def ping_redis(r): print(term.red('Can not connect to Redis server.')) logger.exception(e) raise e - diff --git a/django_q/tests/test_monitor.py b/django_q/tests/test_monitor.py index 797a5a0c..9a266b0b 100644 --- a/django_q/tests/test_monitor.py +++ b/django_q/tests/test_monitor.py @@ -1,10 +1,12 @@ import pytest import redis +from django_q import async from django_q.cluster import Cluster -from django_q.monitor import monitor, Stat, ping_redis +from django_q.monitor import monitor, Stat, ping_redis, info +@pytest.mark.django_db def test_monitor(): assert Stat.get(0).sentinel == 0 c = Cluster() @@ -22,6 +24,20 @@ def test_monitor(): assert found_c is True +@pytest.mark.django_db +def test_info(): + info() + do_sync() + info() + for _ in range(24): + do_sync() + info() + + +def do_sync(): + async('django_q.tests.tasks.countdown', 1, sync=True, save=True) + + @pytest.mark.django_db def test_ping_redis(): r = redis.StrictRedis(port=6388) From 5e2305ad8043488257c2c88523677bb0d9a83cb7 Mon Sep 17 00:00:00 2001 From: Ilan Date: Wed, 12 Aug 2015 12:39:59 +0200 Subject: [PATCH 5/6] docs: adds`qinfo` management command --- docs/_static/info.png | Bin 0 -> 11309 bytes docs/monitor.rst | 20 ++++++++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 docs/_static/info.png diff --git a/docs/_static/info.png b/docs/_static/info.png new file mode 100644 index 0000000000000000000000000000000000000000..1a1ee88e3aa509913c7e35f211ab893f064f5a69 GIT binary patch literal 11309 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 Date: Wed, 12 Aug 2015 13:46:25 +0200 Subject: [PATCH 6/6] v0.5.1 --- django_q/__init__.py | 2 +- docs/conf.py | 2 +- setup.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/django_q/__init__.py b/django_q/__init__.py index 2a8b9d23..5a594273 100644 --- a/django_q/__init__.py +++ b/django_q/__init__.py @@ -9,6 +9,6 @@ from .cluster import Cluster from .monitor import Stat -VERSION = (0, 5, 0) +VERSION = (0, 5, 1) default_app_config = 'django_q.apps.DjangoQConfig' diff --git a/docs/conf.py b/docs/conf.py index 51e01a85..74a22b82 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -72,7 +72,7 @@ # The short X.Y version. version = '0.5' # The full version, including alpha/beta/rc tags. -release = '0.5.0' +release = '0.5.1' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/setup.py b/setup.py index 4a597653..94fb0206 100644 --- a/setup.py +++ b/setup.py @@ -26,7 +26,7 @@ def run(self): setup( name='django-q', - version='0.5.0', + version='0.5.1', author='Ilan Steemers', author_email='koed00@gmail.com', keywords='django task queue worker redis multiprocessing',