Merge pull request #1 from Koed00/master

catchup
This commit is contained in:
Daniel Welch
2017-09-17 13:40:48 -04:00
committed by GitHub
22 changed files with 150 additions and 50 deletions
+4 -4
View File
@@ -6,12 +6,12 @@ services:
python:
- "2.7"
- "3.4"
- "3.6"
env:
- DJANGO=1.10rc1
- DJANGO=1.9.8
- DJANGO=1.8.14
- DJANGO=1.11
- DJANGO=1.10.7
- DJANGO=1.8.18
sudo: false
+2 -1
View File
@@ -3,4 +3,5 @@ include README.rst
include django_q/management/*.py
include django_q/management/commands/*.py
include django_q/migrations/*.py
include django_q/brokers/*.py
include django_q/brokers/*.py
include django_q/tests/*.py
+1 -1
View File
@@ -31,7 +31,7 @@ Requirements
- `Arrow <https://github.com/crsmithdev/arrow>`__
- `Blessed <https://github.com/jquast/blessed>`__
Tested with: Python 2.7 & 3.5. Django 1.8.14, 1.9.8 and 1.10rc1
Tested with: Python 2.7 & 3.6. Django 1.8.18, 1.10.7 and 1.11
Brokers
~~~~~~~
+2 -2
View File
@@ -5,14 +5,14 @@ from django import get_version
myPath = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, myPath)
VERSION = (0, 7, 18)
VERSION = (0, 8, 0)
default_app_config = 'django_q.apps.DjangoQConfig'
# root imports will slowly be deprecated.
# please import from the relevant sub modules
split_version = get_version().split('.')
if split_version[1][0] != '9' and split_version[1][:2] != '10':
if split_version[1] not in ('9', '10', '11'):
from .tasks import async, schedule, result, result_group, fetch, fetch_group, count_group, delete_group, queue_size
from .models import Task, Schedule, Success, Failure
from .cluster import Cluster
+7 -7
View File
@@ -4,12 +4,6 @@ from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from builtins import range
from future import standard_library
standard_library.install_aliases()
# Standard
import importlib
import signal
@@ -30,10 +24,13 @@ from django import db
import signing
import tasks
from django_q.compat import range
from django_q.conf import Conf, logger, psutil, get_ppid, rollbar
from django_q.models import Task, Success, Schedule
from django_q.status import Stat, Status
from django_q.brokers import get_broker
from django_q.signals import pre_execute
class Cluster(object):
@@ -373,8 +370,11 @@ def worker(task_queue, result_queue, timer, timeout=Conf.TIMEOUT):
# We're still going
if not result:
db.close_old_connections()
timer_value = task['kwargs'].pop('timeout', timeout or 0)
# signal execution
pre_execute.send(sender="django_q", func=f, task=task)
# execute the payload
timer.value = task['kwargs'].pop('timeout', timeout or 0) # Busy
timer.value = timer_value # Busy
try:
res = f(*task['args'], **task['kwargs'])
result = (res, True)
+14
View File
@@ -0,0 +1,14 @@
from __future__ import absolute_import
"""
Compatibility layer.
Intentionally replaces use of python-future
"""
# https://github.com/Koed00/django-q/issues/4
try:
range = xrange
except NameError:
range = range
+11 -2
View File
@@ -3,7 +3,7 @@ from django.utils.translation import ugettext as _
from django_q import VERSION
from django_q.conf import Conf
from django_q.monitor import info
from django_q.monitor import info, get_ids
class Command(BaseCommand):
@@ -18,9 +18,18 @@ class Command(BaseCommand):
default=False,
help='Print current configuration.',
)
parser.add_argument(
'--ids',
action='store_true',
dest='ids',
default=False,
help='Print cluster task ID(s) (PIDs).',
)
def handle(self, *args, **options):
if options.get('config', False):
if options.get('ids', True):
get_ids()
elif options.get('config', False):
hide = ['conf', 'IDLE', 'STOPPING', 'STARTING', 'WORKING', 'SIGNAL_NAMES', 'STOPPED']
settings = [a for a in dir(Conf) if not a.startswith('__') and a not in hide]
self.stdout.write('VERSION: {}'.format('.'.join(str(v) for v in VERSION)))
+11
View File
@@ -187,3 +187,14 @@ def info(broker=None):
term.white('{0:.4f}'.format(exec_time))
)
return True
def get_ids():
# prints id (PID) of running clusters
stat = Stat.get_all()
if stat:
for s in stat:
print(s.cluster_id)
else:
print('No clusters appear to be running.')
return True
+5 -1
View File
@@ -1,7 +1,7 @@
import importlib
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.dispatch import receiver, Signal
from django.utils.translation import ugettext_lazy as _
from django_q.conf import logger
@@ -24,3 +24,7 @@ def call_hook(sender, instance, **kwargs):
f(instance)
except Exception as e:
logger.error(_('return hook {} failed on [{}] because {}').format(instance.hook, instance.name, e))
pre_enqueue = Signal(providing_args=["task"])
pre_execute = Signal(providing_args=["func", "task"])
+5 -1
View File
@@ -13,6 +13,7 @@ from django_q.conf import Conf, logger
from django_q.models import Schedule, Task
from django_q.humanhash import uuid
from django_q.brokers import get_broker
from django_q.signals import pre_enqueue
def async(func, *args, **kwargs):
@@ -43,12 +44,15 @@ def async(func, *args, **kwargs):
# finalize
task['kwargs'] = keywords
task['started'] = timezone.now()
# signal it
pre_enqueue.send(sender="django_q", task=task)
# sign it
pack = signing.SignedPackage.dumps(task)
if task.get('sync', False):
return _sync(pack)
# push it
broker.enqueue(pack)
enqueue_id = broker.enqueue(pack)
logger.info('Enqueued {}'.format(enqueue_id))
logger.debug('Pushed {}'.format(tag))
return task['id']
+13 -4
View File
@@ -5,6 +5,7 @@ import pytest
import redis
from django_q.brokers import get_broker, Broker
from django_q.compat import range
from django_q.conf import Conf
from django_q.humanhash import uuid
@@ -170,7 +171,7 @@ def test_ironmq(monkeypatch):
@pytest.mark.skipif(not os.getenv('AWS_ACCESS_KEY_ID'),
reason="requires AWS credentials")
def test_sqs(monkeypatch):
def canceled_sqs(monkeypatch):
monkeypatch.setattr(Conf, 'SQS', {'aws_region': os.getenv('AWS_REGION'),
'aws_access_key_id': os.getenv('AWS_ACCESS_KEY_ID'),
'aws_secret_access_key': os.getenv('AWS_SECRET_ACCESS_KEY')})
@@ -189,15 +190,23 @@ def test_sqs(monkeypatch):
# Retry test
monkeypatch.setattr(Conf, 'RETRY', 1)
broker.enqueue('test')
assert broker.dequeue() is not None
sleep(2)
task = broker.dequeue()[0]
# Sometimes SQS is not linear
task = broker.dequeue()
if not task:
pytest.skip('SQS being weird')
task = task[0]
assert len(task) > 0
broker.acknowledge(task[0])
sleep(2)
# delete job
monkeypatch.setattr(Conf, 'RETRY', 60)
broker.enqueue('test')
task_id = broker.dequeue()[0][0]
sleep(1)
task = broker.dequeue()
if not task:
pytest.skip('SQS being weird')
task_id = task[0][0]
broker.delete(task_id)
assert broker.dequeue() is None
# fail
+1
View File
@@ -3,6 +3,7 @@ from multiprocessing import Event, Queue, Value
import pytest
from django_q.cluster import pusher, worker, monitor
from django_q.compat import range
from django_q.conf import Conf
from django_q.tasks import async, result, fetch, count_group, result_group, fetch_group, delete_group, delete_cached, \
async_iter, Chain, async_chain, Iter, Async
+1
View File
@@ -11,6 +11,7 @@ myPath = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, myPath + '/../')
from django_q.cluster import Cluster, Sentinel, pusher, worker, monitor, save_task
from django_q.compat import range
from django_q.humanhash import DEFAULT_WORDLIST, uuid
from django_q.tasks import fetch, fetch_group, async, result, result_group, count_group, delete_group, queue_size
from django_q.models import Task, Success
+1
View File
@@ -3,6 +3,7 @@ import pytest
from django_q.tasks import async
from django_q.brokers import get_broker
from django_q.cluster import Cluster
from django_q.compat import range
from django_q.monitor import monitor, info
from django_q.status import Stat
from django_q.conf import Conf
+2 -2
View File
@@ -70,9 +70,9 @@ author = 'Ilan Steemers'
# built documents.
#
# The short X.Y version.
version = '0.7'
version = '0.8'
# The full version, including alpha/beta/rc tags.
release = '0.7.18'
release = '0.8.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
+2 -1
View File
@@ -24,7 +24,7 @@ Features
- Rollbar support
Django Q is tested with: Python 2.7 & 3.5. Django 1.8.14, 1.9.8 and 1.10rc1
Django Q is tested with: Python 2.7 & 3.6. Django 1.8.18 LTS, 1.10.7 and 1.11
Contents:
@@ -42,6 +42,7 @@ Contents:
Cluster <cluster>
Monitor <monitor>
Admin <admin>
Signals <signals>
Architecture <architecture>
Examples <examples>
+6 -5
View File
@@ -27,12 +27,12 @@ Installation
Requirements
------------
Django Q is tested for Python 2.7 and 3.5
Django Q is tested for Python 2.7 and 3.6
- `Django <https://www.djangoproject.com>`__
Django Q aims to use as much of Django's standard offerings as possible
The code is tested against Django version `1.8.13` and `1.9.7`.
The code is tested against Django versions `1.8.18 LTS`, `1.10.7` and `1.11`.
- `Django-picklefield <https://github.com/gintas/django-picklefield>`__
@@ -112,12 +112,13 @@ Other known issues are:
Python
~~~~~~
The code is always tested against the latest version of Python 2 and Python 3 and we try to stay compatible with the last two versions of each.
Current tests are performed with Python 2.7.10 and 3.5.
Current tests are performed with Python 2.7.12 and 3.6.1
If you do encounter any regressions with earlier versions, please submit an issue on `github <https://github.com/Koed00/django-q>`__
.. note::
Django 1.7.10 or earlier is not compatible with Python 3.5
Django releases before 1.11 are not officially supported on Python 3.6
Open-source packages
~~~~~~~~~~~~~~~~~~~~
@@ -127,9 +128,9 @@ You can reference the `requirements <https://github.com/Koed00/django-q/blob/mas
Django
~~~~~~
We strive to be compatible with last two major version of Django.
At the moment this means we support the 1.8.14 and 1.9.8 releases.
At the moment this means we support the 1.8.18 LTS, 1.10.7 and 1.11 releases.
You might find that Django Q still works fine with Django 1.7, but new releases are no longer tested for it.
You might find that Django Q still works fine with Django 1.7 and 1.9, but new releases are no longer tested for it.
+43
View File
@@ -0,0 +1,43 @@
Signals
=======
.. py:currentmodule:: django_q
Available signals
-----------------
Django Q emits the following signals during its lifecycle.
Before enqueuing a task
"""""""""""""""""""""""
The ``django_q.signals.pre_enqueue`` signal is emitted before a task is
enqueued. The task dictionary is given as the ``task`` argument.
Before executing a task
"""""""""""""""""""""""
The ``django_q.signals.pre_execute`` signal is emitted before a task is
executed by a worker. This signal provides two arguments:
- ``task``: the task dictionary.
- ``func``: the actual function that will be executed. If the task was created
with a function path, this argument will be the callable function
nonetheless.
Subscribing to a signal
-----------------------
Connecting to a Django Q signal is done in the same manner as any other Django
signal::
from django.dispatch import receiver
from django_q.signals import pre_enqueue, pre_execute
@receiver(pre_enqueue)
def my_pre_enqueue_callback(sender, task, **kwargs):
print("Task {} will be enqueued".format(task["name"]))
@receiver(pre_execute)
def my_pre_execute_callback(sender, func, task, **kwargs):
print("Task {} will be executed by calling {}".format(
task["name"], func))
+2 -2
View File
@@ -265,7 +265,7 @@ Reference
Returns a previously executed task
:param str name: the uuid or name of the task
:param str task_id: the uuid or name of the task
:param int wait: optional milliseconds to wait for a result. -1 for indefinite
:param bool cached: run this against the cache backend.
:returns: A task object
@@ -288,7 +288,7 @@ Reference
Deletes a task from the cache backend
:param task_id: the uuid of the task
:param str task_id: the uuid of the task
:param broker: an optional broker instance
-1
View File
@@ -1,7 +1,6 @@
arrow
blessed
django-picklefield
future
hiredis
redis
psutil
+14 -14
View File
@@ -4,24 +4,24 @@
#
# pip-compile --output-file requirements.txt requirements.in
#
arrow==0.8.0
blessed==1.14.1
boto3==1.3.1
botocore==1.4.38 # via boto3
arrow==0.10.0
blessed==1.14.2
boto3==1.4.4
botocore==1.5.35 # via boto3, s3transfer
django-picklefield==0.3.2
django-redis==4.4.3
docutils==0.12 # via botocore
future==0.15.2
django-redis==4.7.0
docutils==0.13.1 # via botocore
future==0.16.0
hiredis==0.2.0
iron-core==1.2.0 # via iron-mq
iron-mq==0.9
jmespath==0.9.0 # via boto3, botocore
psutil==4.3.0
pymongo==3.3.0
python-dateutil==2.5.3 # via arrow, botocore, iron-core
jmespath==0.9.2 # via boto3, botocore
psutil==5.2.1
pymongo==3.4.0
python-dateutil==2.6.0 # via arrow, botocore, iron-core
redis==2.10.5
requests==2.10.0 # via iron-core, rollbar
rollbar==0.13.2
requests==2.13.0 # via iron-core, rollbar
rollbar==0.13.11
s3transfer==0.1.10 # via boto3
six==1.10.0 # via blessed, python-dateutil, rollbar
wcwidth==0.1.7 # via blessed
+3 -2
View File
@@ -26,7 +26,7 @@ class PyTest(Command):
setup(
name='django-q',
version='0.7.18',
version='0.8.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',
@@ -36,7 +36,7 @@ setup(
license='MIT',
description='A multiprocessing distributed task queue for Django',
long_description=README,
install_requires=['django>=1.7', 'django-picklefield', 'blessed', 'arrow', 'future'],
install_requires=['django>=1.8', 'django-picklefield', 'blessed', 'arrow'],
test_requires=['pytest', 'pytest-django', ],
cmdclass={'test': PyTest},
classifiers=[
@@ -53,6 +53,7 @@ setup(
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Software Development :: Libraries :: Python Modules',
]