From ea30c1d43f210a85d522968f75170b5b73fd7c91 Mon Sep 17 00:00:00 2001 From: Jason McVetta Date: Wed, 12 Feb 2020 17:41:10 +0700 Subject: [PATCH 01/14] add UUID4-based cluster_id --- django_q/cluster.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/django_q/cluster.py b/django_q/cluster.py index 860527c..30cb626 100644 --- a/django_q/cluster.py +++ b/django_q/cluster.py @@ -14,6 +14,7 @@ import importlib import signal import socket import traceback +import uuid # Django from django import db from django.utils import timezone @@ -38,6 +39,7 @@ class Cluster(object): self.stop_event = None self.start_event = None self.pid = current_process().pid + self.cluster_id = uuid.uuid4() self.host = socket.gethostname() self.timeout = Conf.TIMEOUT signal.signal(signal.SIGTERM, self.sig_handler) From d22c916bfccc828093d9c0d60decd68f063bc3a3 Mon Sep 17 00:00:00 2001 From: Jason McVetta Date: Wed, 12 Feb 2020 17:53:52 +0700 Subject: [PATCH 02/14] add cluster_id to Sentinel --- django_q/cluster.py | 5 +++-- django_q/tests/test_cluster.py | 16 +++++++++++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/django_q/cluster.py b/django_q/cluster.py index 30cb626..14766d2 100644 --- a/django_q/cluster.py +++ b/django_q/cluster.py @@ -50,7 +50,7 @@ class Cluster(object): self.stop_event = Event() self.start_event = Event() self.sentinel = Process(target=Sentinel, - args=(self.stop_event, self.start_event, self.broker, self.timeout)) + args=(self.stop_event, self.start_event, self.cluster_id, self.broker, self.timeout)) self.sentinel.start() logger.info(_('Q Cluster-{} starting.').format(self.pid)) while not self.start_event.is_set(): @@ -97,11 +97,12 @@ class Cluster(object): class Sentinel(object): - def __init__(self, stop_event, start_event, broker=None, timeout=Conf.TIMEOUT, start=True): + def __init__(self, stop_event, start_event, cluster_id, broker=None, timeout=Conf.TIMEOUT, start=True): # Make sure we catch signals for the pool signal.signal(signal.SIGINT, signal.SIG_IGN) signal.signal(signal.SIGTERM, signal.SIG_DFL) self.pid = current_process().pid + self.cluster_id = cluster_id self.parent_pid = get_ppid() self.name = current_process().name self.broker = broker or get_broker() diff --git a/django_q/tests/test_cluster.py b/django_q/tests/test_cluster.py index 5e289d7..2c2fbdb 100644 --- a/django_q/tests/test_cluster.py +++ b/django_q/tests/test_cluster.py @@ -3,6 +3,7 @@ import threading from multiprocessing import Event, Value from time import sleep from django.utils import timezone +import uuid as uuidlib import os import pytest @@ -72,7 +73,8 @@ def test_sentinel(): start_event = Event() stop_event = Event() stop_event.set() - s = Sentinel(stop_event, start_event, broker=get_broker('sentinel_test:q')) + cluster_id = uuidlib.uuid4() + s = Sentinel(stop_event, start_event, cluster_id=cluster_id, broker=get_broker('sentinel_test:q')) assert start_event.is_set() assert s.status() == Conf.STOPPED @@ -256,9 +258,10 @@ def test_timeout(broker, cluster_config_timeout, async_task_kwargs): async_task('time.sleep', 5, broker=broker, **async_task_kwargs) start_event = Event() stop_event = Event() + cluster_id = uuidlib.uuid4() # Set a timer to stop the Sentinel threading.Timer(3, stop_event.set).start() - s = Sentinel(stop_event, start_event, broker=broker, timeout=cluster_config_timeout) + s = Sentinel(stop_event, start_event, cluster_id=cluster_id, broker=broker, timeout=cluster_config_timeout) assert start_event.is_set() assert s.status() == Conf.STOPPED assert s.reincarnations == 1 @@ -279,9 +282,10 @@ def test_timeout_task_finishes(broker, cluster_config_timeout, async_task_kwargs async_task('time.sleep', 3, broker=broker, **async_task_kwargs) start_event = Event() stop_event = Event() + cluster_id = uuidlib.uuid4() # Set a timer to stop the Sentinel threading.Timer(6, stop_event.set).start() - s = Sentinel(stop_event, start_event, broker=broker, timeout=cluster_config_timeout) + s = Sentinel(stop_event, start_event, cluster_id=cluster_id, broker=broker, timeout=cluster_config_timeout) assert start_event.is_set() assert s.status() == Conf.STOPPED assert s.reincarnations == 0 @@ -297,12 +301,13 @@ def test_recycle(broker, monkeypatch): async_task('django_q.tests.tasks.multiply', 2, 2, broker=broker) start_event = Event() stop_event = Event() + cluster_id = uuidlib.uuid4() # override settings monkeypatch.setattr(Conf, 'RECYCLE', 2) monkeypatch.setattr(Conf, 'WORKERS', 1) # set a timer to stop the Sentinel threading.Timer(3, stop_event.set).start() - s = Sentinel(stop_event, start_event, broker=broker) + s = Sentinel(stop_event, start_event, cluster_id=cluster_id, broker=broker) assert start_event.is_set() assert s.status() == Conf.STOPPED assert s.reincarnations == 1 @@ -333,7 +338,8 @@ def test_bad_secret(broker, monkeypatch): stop_event = Event() stop_event.set() start_event = Event() - s = Sentinel(stop_event, start_event, broker=broker, start=False) + cluster_id = uuidlib.uuid4() + s = Sentinel(stop_event, start_event, cluster_id=cluster_id, broker=broker, start=False) Stat(s).save() # change the SECRET monkeypatch.setattr(Conf, "SECRET_KEY", "OOPS") From 14a602ee8b6fe8cee142a51441355a97db5056a7 Mon Sep 17 00:00:00 2001 From: Jason McVetta Date: Wed, 12 Feb 2020 18:23:47 +0700 Subject: [PATCH 03/14] use both pid and cluster_id --- django_q/cluster.py | 4 ++-- django_q/status.py | 11 ++++++----- django_q/tests/test_cluster.py | 2 +- django_q/tests/test_monitor.py | 6 ++++-- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/django_q/cluster.py b/django_q/cluster.py index 14766d2..4e755c1 100644 --- a/django_q/cluster.py +++ b/django_q/cluster.py @@ -76,8 +76,8 @@ class Cluster(object): @property def stat(self): if self.sentinel: - return Stat.get(self.pid) - return Status(self.pid) + return Stat.get(pid=self.pid, cluster_id=self.cluster_id) + return Status(pid=self.pid, cluster_id=self.cluster_id) @property def is_starting(self): diff --git a/django_q/status.py b/django_q/status.py index 51f32ee..06402a9 100644 --- a/django_q/status.py +++ b/django_q/status.py @@ -8,11 +8,12 @@ from django_q.signing import SignedPackage, BadSignature class Status(object): """Cluster status base class.""" - def __init__(self, pid): + def __init__(self, pid, cluster_id): self.workers = [] self.tob = None self.reincarnations = 0 - self.cluster_id = pid + self.pid = pid + self.cluster_id = cluster_id self.sentinel = 0 self.status = Conf.STOPPED self.done_q_size = 0 @@ -27,7 +28,7 @@ class Stat(Status): """Status object for Cluster monitoring.""" def __init__(self, sentinel): - super(Stat, self).__init__(sentinel.parent_pid or sentinel.pid) + super(Stat, self).__init__(sentinel.parent_pid or sentinel.pid, cluster_id=sentinel.cluster_id) self.broker = sentinel.broker or get_broker() self.tob = sentinel.tob self.reincarnations = sentinel.reincarnations @@ -72,7 +73,7 @@ class Stat(Status): return self.done_q_size + self.task_q_size == 0 @staticmethod - def get(cluster_id, broker=None): + def get(pid, cluster_id, broker=None): """ gets the current status for the cluster :param cluster_id: id of the cluster @@ -86,7 +87,7 @@ class Stat(Status): return SignedPackage.loads(pack) except BadSignature: return None - return Status(cluster_id) + return Status(pid=pid, cluster_id=cluster_id) @staticmethod def get_all(broker=None): diff --git a/django_q/tests/test_cluster.py b/django_q/tests/test_cluster.py index 2c2fbdb..f3905f9 100644 --- a/django_q/tests/test_cluster.py +++ b/django_q/tests/test_cluster.py @@ -345,7 +345,7 @@ def test_bad_secret(broker, monkeypatch): monkeypatch.setattr(Conf, "SECRET_KEY", "OOPS") stat = Stat.get_all() assert len(stat) == 0 - assert Stat.get(s.parent_pid) is None + assert Stat.get(pid=s.parent_pid, cluster_id=cluster_id) is None task_queue = Queue() pusher(task_queue, stop_event, broker=broker) result_queue = Queue() diff --git a/django_q/tests/test_monitor.py b/django_q/tests/test_monitor.py index 5719973..a7b19a6 100644 --- a/django_q/tests/test_monitor.py +++ b/django_q/tests/test_monitor.py @@ -1,4 +1,5 @@ import pytest +import uuid from django_q.tasks import async_task from django_q.brokers import get_broker @@ -10,7 +11,8 @@ from django_q.conf import Conf @pytest.mark.django_db def test_monitor(monkeypatch): - assert Stat.get(0).sentinel == 0 + cluster_id = uuid.uuid4() + assert Stat.get(pid=0, cluster_id=4).sentinel == 0 c = Cluster() c.start() stats = monitor(run_once=True) @@ -18,7 +20,7 @@ def test_monitor(monkeypatch): assert len(stats) > 0 found_c = False for stat in stats: - if stat.cluster_id == c.pid: + if stat.cluster_id == c.cluster_id: found_c = True assert stat.uptime() > 0 assert stat.empty_queues() is True From 4529c3806799f8b37cb9d0bfd489cccfe6db427b Mon Sep 17 00:00:00 2001 From: Jason McVetta Date: Wed, 12 Feb 2020 18:26:53 +0700 Subject: [PATCH 04/14] log cluster_id instead of pid --- django_q/cluster.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/django_q/cluster.py b/django_q/cluster.py index 4e755c1..bece2df 100644 --- a/django_q/cluster.py +++ b/django_q/cluster.py @@ -52,7 +52,7 @@ class Cluster(object): self.sentinel = Process(target=Sentinel, args=(self.stop_event, self.start_event, self.cluster_id, self.broker, self.timeout)) self.sentinel.start() - logger.info(_('Q Cluster-{} starting.').format(self.pid)) + logger.info(_('Q Cluster-{} starting.').format(self.cluster_id)) while not self.start_event.is_set(): sleep(0.1) return self.pid @@ -60,10 +60,10 @@ class Cluster(object): def stop(self): if not self.sentinel.is_alive(): return False - logger.info(_('Q Cluster-{} stopping.').format(self.pid)) + logger.info(_('Q Cluster-{} stopping.').format(self.cluster_id)) self.stop_event.set() self.sentinel.join() - logger.info(_('Q Cluster-{} has stopped.').format(self.pid)) + logger.info(_('Q Cluster-{} has stopped.').format(self.cluster_id)) self.start_event = None self.stop_event = None return True From cb01620a5d71ba81c99b17a2d277303fcf96f04e Mon Sep 17 00:00:00 2001 From: Jason McVetta Date: Wed, 12 Feb 2020 18:43:31 +0700 Subject: [PATCH 05/14] truncate cluster_id UUID to fit column --- django_q/monitor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/django_q/monitor.py b/django_q/monitor.py index 8fd233d..14a28a3 100644 --- a/django_q/monitor.py +++ b/django_q/monitor.py @@ -72,7 +72,7 @@ def monitor(run_once=False, broker=None): uptime = '%d:%02d:%02d' % (hours, minutes, seconds) # print to the terminal print(term.move(i, 0) + term.center(stat.host[:col_width - 1], width=col_width - 1)) - print(term.move(i, 1 * col_width) + term.center(stat.cluster_id, width=col_width - 1)) + print(term.move(i, 1 * col_width) + term.center(stat.cluster_id[:8], width=col_width - 1)) print(term.move(i, 2 * col_width) + term.center(status, width=col_width - 1)) print(term.move(i, 3 * col_width) + term.center(workers, width=col_width - 1)) print(term.move(i, 4 * col_width) + term.center(tasks, width=col_width - 1)) From a37d3b7af04de946a1a577acaf683d6d9b85c49c Mon Sep 17 00:00:00 2001 From: Jason McVetta Date: Wed, 12 Feb 2020 18:50:46 +0700 Subject: [PATCH 06/14] wider column for cluster_id, and cast to string --- django_q/monitor.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/django_q/monitor.py b/django_q/monitor.py index 14a28a3..632c2e5 100644 --- a/django_q/monitor.py +++ b/django_q/monitor.py @@ -25,13 +25,14 @@ def monitor(run_once=False, broker=None): val = None start_width = int(term.width / 8) while val not in (u'q', u'Q',): - col_width = int(term.width / 8) + cluster_id_width = 36 # UUID4 + col_width = int((term.width - cluster_id_width) / 7) # In case of resize if col_width != start_width: print(term.clear()) start_width = col_width print(term.move(0, 0) + term.black_on_green(term.center(_('Host'), width=col_width - 1))) - print(term.move(0, 1 * col_width) + term.black_on_green(term.center(_('Id'), width=col_width - 1))) + print(term.move(0, 1 * col_width) + term.black_on_green(term.center(_('Id'), width=cluster_id_width - 1))) print(term.move(0, 2 * col_width) + term.black_on_green(term.center(_('State'), width=col_width - 1))) print(term.move(0, 3 * col_width) + term.black_on_green(term.center(_('Pool'), width=col_width - 1))) print(term.move(0, 4 * col_width) + term.black_on_green(term.center(_('TQ'), width=col_width - 1))) @@ -72,7 +73,7 @@ def monitor(run_once=False, broker=None): uptime = '%d:%02d:%02d' % (hours, minutes, seconds) # print to the terminal print(term.move(i, 0) + term.center(stat.host[:col_width - 1], width=col_width - 1)) - print(term.move(i, 1 * col_width) + term.center(stat.cluster_id[:8], width=col_width - 1)) + print(term.move(i, 1 * col_width) + term.center(str(stat.cluster_id), width=cluster_id_width - 1)) print(term.move(i, 2 * col_width) + term.center(status, width=col_width - 1)) print(term.move(i, 3 * col_width) + term.center(workers, width=col_width - 1)) print(term.move(i, 4 * col_width) + term.center(tasks, width=col_width - 1)) From db70d14754add3bbc6a6ab2ac67b67f32441163c Mon Sep 17 00:00:00 2001 From: Jason McVetta Date: Wed, 12 Feb 2020 18:51:41 +0700 Subject: [PATCH 07/14] terminal position --- django_q/monitor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/django_q/monitor.py b/django_q/monitor.py index 632c2e5..bd87fa6 100644 --- a/django_q/monitor.py +++ b/django_q/monitor.py @@ -74,7 +74,7 @@ def monitor(run_once=False, broker=None): # print to the terminal print(term.move(i, 0) + term.center(stat.host[:col_width - 1], width=col_width - 1)) print(term.move(i, 1 * col_width) + term.center(str(stat.cluster_id), width=cluster_id_width - 1)) - print(term.move(i, 2 * col_width) + term.center(status, width=col_width - 1)) + print(term.move(i, 2 * cluster_id_width) + term.center(status, width=col_width - 1)) print(term.move(i, 3 * col_width) + term.center(workers, width=col_width - 1)) print(term.move(i, 4 * col_width) + term.center(tasks, width=col_width - 1)) print(term.move(i, 5 * col_width) + term.center(results, width=col_width - 1)) From 7f9f6c3a048321c5eed84d80bd9b89868ed206c9 Mon Sep 17 00:00:00 2001 From: Jason McVetta Date: Wed, 12 Feb 2020 18:52:24 +0700 Subject: [PATCH 08/14] Revert "terminal position" This reverts commit db70d14754add3bbc6a6ab2ac67b67f32441163c. --- django_q/monitor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/django_q/monitor.py b/django_q/monitor.py index bd87fa6..632c2e5 100644 --- a/django_q/monitor.py +++ b/django_q/monitor.py @@ -74,7 +74,7 @@ def monitor(run_once=False, broker=None): # print to the terminal print(term.move(i, 0) + term.center(stat.host[:col_width - 1], width=col_width - 1)) print(term.move(i, 1 * col_width) + term.center(str(stat.cluster_id), width=cluster_id_width - 1)) - print(term.move(i, 2 * cluster_id_width) + term.center(status, width=col_width - 1)) + print(term.move(i, 2 * col_width) + term.center(status, width=col_width - 1)) print(term.move(i, 3 * col_width) + term.center(workers, width=col_width - 1)) print(term.move(i, 4 * col_width) + term.center(tasks, width=col_width - 1)) print(term.move(i, 5 * col_width) + term.center(results, width=col_width - 1)) From abc8b397fc8366f389fb47dd2bf48eb980529146 Mon Sep 17 00:00:00 2001 From: Jason McVetta Date: Wed, 12 Feb 2020 18:52:25 +0700 Subject: [PATCH 09/14] Revert "wider column for cluster_id, and cast to string" This reverts commit a37d3b7af04de946a1a577acaf683d6d9b85c49c. --- django_q/monitor.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/django_q/monitor.py b/django_q/monitor.py index 632c2e5..14a28a3 100644 --- a/django_q/monitor.py +++ b/django_q/monitor.py @@ -25,14 +25,13 @@ def monitor(run_once=False, broker=None): val = None start_width = int(term.width / 8) while val not in (u'q', u'Q',): - cluster_id_width = 36 # UUID4 - col_width = int((term.width - cluster_id_width) / 7) + col_width = int(term.width / 8) # In case of resize if col_width != start_width: print(term.clear()) start_width = col_width print(term.move(0, 0) + term.black_on_green(term.center(_('Host'), width=col_width - 1))) - print(term.move(0, 1 * col_width) + term.black_on_green(term.center(_('Id'), width=cluster_id_width - 1))) + print(term.move(0, 1 * col_width) + term.black_on_green(term.center(_('Id'), width=col_width - 1))) print(term.move(0, 2 * col_width) + term.black_on_green(term.center(_('State'), width=col_width - 1))) print(term.move(0, 3 * col_width) + term.black_on_green(term.center(_('Pool'), width=col_width - 1))) print(term.move(0, 4 * col_width) + term.black_on_green(term.center(_('TQ'), width=col_width - 1))) @@ -73,7 +72,7 @@ def monitor(run_once=False, broker=None): uptime = '%d:%02d:%02d' % (hours, minutes, seconds) # print to the terminal print(term.move(i, 0) + term.center(stat.host[:col_width - 1], width=col_width - 1)) - print(term.move(i, 1 * col_width) + term.center(str(stat.cluster_id), width=cluster_id_width - 1)) + print(term.move(i, 1 * col_width) + term.center(stat.cluster_id[:8], width=col_width - 1)) print(term.move(i, 2 * col_width) + term.center(status, width=col_width - 1)) print(term.move(i, 3 * col_width) + term.center(workers, width=col_width - 1)) print(term.move(i, 4 * col_width) + term.center(tasks, width=col_width - 1)) From aa51413d81a4ea9b7d7a69e8a7b429386ec6a574 Mon Sep 17 00:00:00 2001 From: Jason McVetta Date: Wed, 12 Feb 2020 18:52:45 +0700 Subject: [PATCH 10/14] cast cluster_id UUID to str --- django_q/monitor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/django_q/monitor.py b/django_q/monitor.py index 14a28a3..f318923 100644 --- a/django_q/monitor.py +++ b/django_q/monitor.py @@ -72,7 +72,7 @@ def monitor(run_once=False, broker=None): uptime = '%d:%02d:%02d' % (hours, minutes, seconds) # print to the terminal print(term.move(i, 0) + term.center(stat.host[:col_width - 1], width=col_width - 1)) - print(term.move(i, 1 * col_width) + term.center(stat.cluster_id[:8], width=col_width - 1)) + print(term.move(i, 1 * col_width) + term.center(str(stat.cluster_id)[:8], width=col_width - 1)) print(term.move(i, 2 * col_width) + term.center(status, width=col_width - 1)) print(term.move(i, 3 * col_width) + term.center(workers, width=col_width - 1)) print(term.move(i, 4 * col_width) + term.center(tasks, width=col_width - 1)) From 93a8c3520c9194eac842ca8aba166923b813b71b Mon Sep 17 00:00:00 2001 From: Jason McVetta Date: Wed, 12 Feb 2020 18:56:54 +0700 Subject: [PATCH 11/14] truncate cluster_id from the other end --- django_q/monitor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/django_q/monitor.py b/django_q/monitor.py index f318923..bccb3ac 100644 --- a/django_q/monitor.py +++ b/django_q/monitor.py @@ -72,7 +72,7 @@ def monitor(run_once=False, broker=None): uptime = '%d:%02d:%02d' % (hours, minutes, seconds) # print to the terminal print(term.move(i, 0) + term.center(stat.host[:col_width - 1], width=col_width - 1)) - print(term.move(i, 1 * col_width) + term.center(str(stat.cluster_id)[:8], width=col_width - 1)) + print(term.move(i, 1 * col_width) + term.center(str(stat.cluster_id)[-8:], width=col_width - 1)) print(term.move(i, 2 * col_width) + term.center(status, width=col_width - 1)) print(term.move(i, 3 * col_width) + term.center(workers, width=col_width - 1)) print(term.move(i, 4 * col_width) + term.center(tasks, width=col_width - 1)) From 3d394b25e41f030b6da180d47f6e3610b2415287 Mon Sep 17 00:00:00 2001 From: Jason McVetta Date: Thu, 13 Feb 2020 13:12:25 +0700 Subject: [PATCH 12/14] bump version from 1.1.0 -> 1.2.0 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 9cb14c4..d440468 100644 --- a/setup.py +++ b/setup.py @@ -26,7 +26,7 @@ class PyTest(Command): setup( name='django-q', - version='1.1.0', + version='1.2.0', author='Ilan Steemers', author_email='koed0@gmail.com', keywords='django distributed task queue worker scheduler cron redis disque ironmq sqs orm mongodb multiprocessing rollbar', From 35848cc80da9f346f6ec2d6f192555d8edc2adcb Mon Sep 17 00:00:00 2001 From: Jason McVetta Date: Thu, 13 Feb 2020 18:17:00 +0700 Subject: [PATCH 13/14] fix typo --- django_q/tests/test_monitor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/django_q/tests/test_monitor.py b/django_q/tests/test_monitor.py index a7b19a6..5964a31 100644 --- a/django_q/tests/test_monitor.py +++ b/django_q/tests/test_monitor.py @@ -12,7 +12,7 @@ from django_q.conf import Conf @pytest.mark.django_db def test_monitor(monkeypatch): cluster_id = uuid.uuid4() - assert Stat.get(pid=0, cluster_id=4).sentinel == 0 + assert Stat.get(pid=0, cluster_id=cluster_id).sentinel == 0 c = Cluster() c.start() stats = monitor(run_once=True) From 93fab1e87fb60e0a5521a9d97b18645992cc70a1 Mon Sep 17 00:00:00 2001 From: Jason McVetta Date: Thu, 13 Feb 2020 18:17:46 +0700 Subject: [PATCH 14/14] Revert "bump version from 1.1.0 -> 1.2.0" This reverts commit 3d394b25e41f030b6da180d47f6e3610b2415287. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index d440468..9cb14c4 100644 --- a/setup.py +++ b/setup.py @@ -26,7 +26,7 @@ class PyTest(Command): setup( name='django-q', - version='1.2.0', + version='1.1.0', author='Ilan Steemers', author_email='koed0@gmail.com', keywords='django distributed task queue worker scheduler cron redis disque ironmq sqs orm mongodb multiprocessing rollbar',