mirror of
https://github.com/django-q2/django-q2.git
synced 2026-10-04 16:58:11 +08:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -1,9 +1,9 @@
|
|||||||
import os
|
# import os
|
||||||
import sys
|
# import sys
|
||||||
import django
|
import django
|
||||||
|
|
||||||
myPath = os.path.dirname(os.path.abspath(__file__))
|
# myPath = os.path.dirname(os.path.abspath(__file__))
|
||||||
sys.path.insert(0, myPath)
|
# sys.path.insert(0, myPath)
|
||||||
|
|
||||||
VERSION = (0, 9, 2)
|
VERSION = (0, 9, 2)
|
||||||
|
|
||||||
|
|||||||
+12
-13
@@ -21,12 +21,11 @@ from django.utils.translation import ugettext_lazy as _
|
|||||||
from django import db
|
from django import db
|
||||||
|
|
||||||
# Local
|
# Local
|
||||||
import signing
|
from django_q import tasks
|
||||||
import tasks
|
|
||||||
|
|
||||||
from django_q.compat import range
|
from django_q.compat import range
|
||||||
from django_q.conf import Conf, logger, psutil, get_ppid, error_reporter, rollbar
|
from django_q.conf import Conf, logger, psutil, get_ppid, error_reporter, rollbar
|
||||||
from django_q.models import Task, Success, Schedule
|
from django_q.models import Task, Success, Schedule
|
||||||
|
from django_q.signing import SignedPackage, BadSignature
|
||||||
from django_q.status import Stat, Status
|
from django_q.status import Stat, Status
|
||||||
from django_q.brokers import get_broker
|
from django_q.brokers import get_broker
|
||||||
from django_q.signals import pre_execute
|
from django_q.signals import pre_execute
|
||||||
@@ -297,8 +296,8 @@ def pusher(task_queue, event, broker=None):
|
|||||||
ack_id = task[0]
|
ack_id = task[0]
|
||||||
# unpack the task
|
# unpack the task
|
||||||
try:
|
try:
|
||||||
task = signing.SignedPackage.loads(task[1])
|
task = SignedPackage.loads(task[1])
|
||||||
except (TypeError, signing.BadSignature) as e:
|
except (TypeError, BadSignature) as e:
|
||||||
logger.error(e)
|
logger.error(e)
|
||||||
broker.fail(ack_id)
|
broker.fail(ack_id)
|
||||||
continue
|
continue
|
||||||
@@ -325,12 +324,12 @@ def monitor(result_queue, broker=None):
|
|||||||
save_cached(task, broker)
|
save_cached(task, broker)
|
||||||
else:
|
else:
|
||||||
save_task(task, broker)
|
save_task(task, broker)
|
||||||
# acknowledge and log the result
|
# acknowledge result
|
||||||
|
ack_id = task.pop('ack_id', False)
|
||||||
|
if ack_id and (task['success'] or task.get('ack_failure', False)):
|
||||||
|
broker.acknowledge(ack_id)
|
||||||
|
# log the result
|
||||||
if task['success']:
|
if task['success']:
|
||||||
# acknowledge
|
|
||||||
ack_id = task.pop('ack_id', False)
|
|
||||||
if ack_id:
|
|
||||||
broker.acknowledge(ack_id)
|
|
||||||
# log success
|
# log success
|
||||||
logger.info(_("Processed [{}]").format(task['name']))
|
logger.info(_("Processed [{}]").format(task['name']))
|
||||||
else:
|
else:
|
||||||
@@ -456,11 +455,11 @@ def save_cached(task, broker):
|
|||||||
if iter_count and len(group_list) == iter_count - 1:
|
if iter_count and len(group_list) == iter_count - 1:
|
||||||
group_args = '{}:{}:args'.format(broker.list_key, group)
|
group_args = '{}:{}:args'.format(broker.list_key, group)
|
||||||
# collate the results into a Task result
|
# collate the results into a Task result
|
||||||
results = [signing.SignedPackage.loads(broker.cache.get(k))['result'] for k in group_list]
|
results = [SignedPackage.loads(broker.cache.get(k))['result'] for k in group_list]
|
||||||
results.append(task['result'])
|
results.append(task['result'])
|
||||||
task['result'] = results
|
task['result'] = results
|
||||||
task['id'] = group
|
task['id'] = group
|
||||||
task['args'] = signing.SignedPackage.loads(broker.cache.get(group_args))
|
task['args'] = SignedPackage.loads(broker.cache.get(group_args))
|
||||||
task.pop('iter_count', None)
|
task.pop('iter_count', None)
|
||||||
task.pop('group', None)
|
task.pop('group', None)
|
||||||
if task.get('iter_cached', None):
|
if task.get('iter_cached', None):
|
||||||
@@ -479,7 +478,7 @@ def save_cached(task, broker):
|
|||||||
tasks.async_chain(task['chain'], group=group, cached=task['cached'], sync=task['sync'], broker=broker)
|
tasks.async_chain(task['chain'], group=group, cached=task['cached'], sync=task['sync'], broker=broker)
|
||||||
# save the task
|
# save the task
|
||||||
broker.cache.set(task_key,
|
broker.cache.set(task_key,
|
||||||
signing.SignedPackage.dumps(task),
|
SignedPackage.dumps(task),
|
||||||
timeout)
|
timeout)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(e)
|
logger.error(e)
|
||||||
|
|||||||
@@ -110,6 +110,11 @@ class Conf(object):
|
|||||||
# Number of seconds to wait for a worker to finish.
|
# Number of seconds to wait for a worker to finish.
|
||||||
TIMEOUT = conf.get('timeout', None)
|
TIMEOUT = conf.get('timeout', None)
|
||||||
|
|
||||||
|
# Whether to acknowledge unsuccessful tasks.
|
||||||
|
# This causes failed tasks to be considered delivered, thereby removing them from
|
||||||
|
# the task queue. Defaults to False.
|
||||||
|
ACK_FAILURES = conf.get('ack_failures', False)
|
||||||
|
|
||||||
# Number of seconds to wait for acknowledgement before retrying a task
|
# Number of seconds to wait for acknowledgement before retrying a task
|
||||||
# Only works with brokers that guarantee delivery. Defaults to 60 seconds.
|
# Only works with brokers that guarantee delivery. Defaults to 60 seconds.
|
||||||
RETRY = conf.get('retry', 60)
|
RETRY = conf.get('retry', 60)
|
||||||
|
|||||||
+6
-6
@@ -2,7 +2,7 @@ import socket
|
|||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django_q.brokers import get_broker
|
from django_q.brokers import get_broker
|
||||||
from django_q.conf import Conf, logger
|
from django_q.conf import Conf, logger
|
||||||
import signing
|
from django_q.signing import SignedPackage, BadSignature
|
||||||
|
|
||||||
|
|
||||||
class Status(object):
|
class Status(object):
|
||||||
@@ -64,7 +64,7 @@ class Stat(Status):
|
|||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
try:
|
try:
|
||||||
self.broker.set_stat(self.key, signing.SignedPackage.dumps(self, True), 3)
|
self.broker.set_stat(self.key, SignedPackage.dumps(self, True), 3)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(e)
|
logger.error(e)
|
||||||
|
|
||||||
@@ -83,8 +83,8 @@ class Stat(Status):
|
|||||||
pack = broker.get_stat(Stat.get_key(cluster_id))
|
pack = broker.get_stat(Stat.get_key(cluster_id))
|
||||||
if pack:
|
if pack:
|
||||||
try:
|
try:
|
||||||
return signing.SignedPackage.loads(pack)
|
return SignedPackage.loads(pack)
|
||||||
except signing.BadSignature:
|
except BadSignature:
|
||||||
return None
|
return None
|
||||||
return Status(cluster_id)
|
return Status(cluster_id)
|
||||||
|
|
||||||
@@ -101,8 +101,8 @@ class Stat(Status):
|
|||||||
packs = broker.get_stats('{}:*'.format(Conf.Q_STAT)) or []
|
packs = broker.get_stats('{}:*'.format(Conf.Q_STAT)) or []
|
||||||
for pack in packs:
|
for pack in packs:
|
||||||
try:
|
try:
|
||||||
stats.append(signing.SignedPackage.loads(pack))
|
stats.append(SignedPackage.loads(pack))
|
||||||
except signing.BadSignature:
|
except BadSignature:
|
||||||
continue
|
continue
|
||||||
return stats
|
return stats
|
||||||
|
|
||||||
|
|||||||
+52
-46
@@ -1,4 +1,6 @@
|
|||||||
"""Provides task functionality."""
|
"""Provides task functionality."""
|
||||||
|
# Standard
|
||||||
|
from time import sleep, time
|
||||||
from multiprocessing import Value
|
from multiprocessing import Value
|
||||||
|
|
||||||
# django
|
# django
|
||||||
@@ -6,9 +8,7 @@ from django.db import IntegrityError
|
|||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
# local
|
# local
|
||||||
import time
|
from django_q.signing import SignedPackage
|
||||||
import signing
|
|
||||||
import cluster
|
|
||||||
from django_q.conf import Conf, logger
|
from django_q.conf import Conf, logger
|
||||||
from django_q.models import Schedule, Task
|
from django_q.models import Schedule, Task
|
||||||
from django_q.humanhash import uuid
|
from django_q.humanhash import uuid
|
||||||
@@ -20,7 +20,7 @@ from django_q.queues import Queue
|
|||||||
def async(func, *args, **kwargs):
|
def async(func, *args, **kwargs):
|
||||||
"""Queue a task for the cluster."""
|
"""Queue a task for the cluster."""
|
||||||
keywords = kwargs.copy()
|
keywords = kwargs.copy()
|
||||||
opt_keys = ('hook', 'group', 'save', 'sync', 'cached', 'iter_count', 'iter_cached', 'chain', 'broker')
|
opt_keys = ('hook', 'group', 'save', 'sync', 'cached', 'ack_failure', 'iter_count', 'iter_cached', 'chain', 'broker')
|
||||||
q_options = keywords.pop('q_options', {})
|
q_options = keywords.pop('q_options', {})
|
||||||
# get an id
|
# get an id
|
||||||
tag = uuid()
|
tag = uuid()
|
||||||
@@ -42,13 +42,15 @@ def async(func, *args, **kwargs):
|
|||||||
task['cached'] = Conf.CACHED
|
task['cached'] = Conf.CACHED
|
||||||
if 'sync' not in task and Conf.SYNC:
|
if 'sync' not in task and Conf.SYNC:
|
||||||
task['sync'] = Conf.SYNC
|
task['sync'] = Conf.SYNC
|
||||||
|
if 'ack_failure' not in task and Conf.ACK_FAILURES:
|
||||||
|
task['ack_failure'] = Conf.ACK_FAILURES
|
||||||
# finalize
|
# finalize
|
||||||
task['kwargs'] = keywords
|
task['kwargs'] = keywords
|
||||||
task['started'] = timezone.now()
|
task['started'] = timezone.now()
|
||||||
# signal it
|
# signal it
|
||||||
pre_enqueue.send(sender="django_q", task=task)
|
pre_enqueue.send(sender="django_q", task=task)
|
||||||
# sign it
|
# sign it
|
||||||
pack = signing.SignedPackage.dumps(task)
|
pack = SignedPackage.dumps(task)
|
||||||
if task.get('sync', False):
|
if task.get('sync', False):
|
||||||
return _sync(pack)
|
return _sync(pack)
|
||||||
# push it
|
# push it
|
||||||
@@ -112,14 +114,14 @@ def result(task_id, wait=0, cached=Conf.CACHED):
|
|||||||
"""
|
"""
|
||||||
if cached:
|
if cached:
|
||||||
return result_cached(task_id, wait)
|
return result_cached(task_id, wait)
|
||||||
start = time.time()
|
start = time()
|
||||||
while True:
|
while True:
|
||||||
r = Task.get_result(task_id)
|
r = Task.get_result(task_id)
|
||||||
if r:
|
if r:
|
||||||
return r
|
return r
|
||||||
if (time.time() - start) * 1000 >= wait >= 0:
|
if (time() - start) * 1000 >= wait >= 0:
|
||||||
break
|
break
|
||||||
time.sleep(0.01)
|
sleep(0.01)
|
||||||
|
|
||||||
|
|
||||||
def result_cached(task_id, wait=0, broker=None):
|
def result_cached(task_id, wait=0, broker=None):
|
||||||
@@ -128,14 +130,14 @@ def result_cached(task_id, wait=0, broker=None):
|
|||||||
"""
|
"""
|
||||||
if not broker:
|
if not broker:
|
||||||
broker = get_broker()
|
broker = get_broker()
|
||||||
start = time.time()
|
start = time()
|
||||||
while True:
|
while True:
|
||||||
r = broker.cache.get('{}:{}'.format(broker.list_key, task_id))
|
r = broker.cache.get('{}:{}'.format(broker.list_key, task_id))
|
||||||
if r:
|
if r:
|
||||||
return signing.SignedPackage.loads(r)['result']
|
return SignedPackage.loads(r)['result']
|
||||||
if (time.time() - start) * 1000 >= wait >= 0:
|
if (time() - start) * 1000 >= wait >= 0:
|
||||||
break
|
break
|
||||||
time.sleep(0.01)
|
sleep(0.01)
|
||||||
|
|
||||||
|
|
||||||
def result_group(group_id, failures=False, wait=0, count=None, cached=Conf.CACHED):
|
def result_group(group_id, failures=False, wait=0, count=None, cached=Conf.CACHED):
|
||||||
@@ -150,19 +152,19 @@ def result_group(group_id, failures=False, wait=0, count=None, cached=Conf.CACHE
|
|||||||
"""
|
"""
|
||||||
if cached:
|
if cached:
|
||||||
return result_group_cached(group_id, failures, wait, count)
|
return result_group_cached(group_id, failures, wait, count)
|
||||||
start = time.time()
|
start = time()
|
||||||
if count:
|
if count:
|
||||||
while True:
|
while True:
|
||||||
if count_group(group_id) == count or wait and (time.time() - start) * 1000 >= wait >= 0:
|
if count_group(group_id) == count or wait and (time() - start) * 1000 >= wait >= 0:
|
||||||
break
|
break
|
||||||
time.sleep(0.01)
|
sleep(0.01)
|
||||||
while True:
|
while True:
|
||||||
r = Task.get_result_group(group_id, failures)
|
r = Task.get_result_group(group_id, failures)
|
||||||
if r:
|
if r:
|
||||||
return r
|
return r
|
||||||
if (time.time() - start) * 1000 >= wait >= 0:
|
if (time() - start) * 1000 >= wait >= 0:
|
||||||
break
|
break
|
||||||
time.sleep(0.01)
|
sleep(0.01)
|
||||||
|
|
||||||
|
|
||||||
def result_group_cached(group_id, failures=False, wait=0, count=None, broker=None):
|
def result_group_cached(group_id, failures=False, wait=0, count=None, broker=None):
|
||||||
@@ -171,24 +173,24 @@ def result_group_cached(group_id, failures=False, wait=0, count=None, broker=Non
|
|||||||
"""
|
"""
|
||||||
if not broker:
|
if not broker:
|
||||||
broker = get_broker()
|
broker = get_broker()
|
||||||
start = time.time()
|
start = time()
|
||||||
if count:
|
if count:
|
||||||
while True:
|
while True:
|
||||||
if count_group_cached(group_id) == count or wait and (time.time() - start) * 1000 >= wait > 0:
|
if count_group_cached(group_id) == count or wait and (time() - start) * 1000 >= wait > 0:
|
||||||
break
|
break
|
||||||
time.sleep(0.01)
|
sleep(0.01)
|
||||||
while True:
|
while True:
|
||||||
group_list = broker.cache.get('{}:{}:keys'.format(broker.list_key, group_id))
|
group_list = broker.cache.get('{}:{}:keys'.format(broker.list_key, group_id))
|
||||||
if group_list:
|
if group_list:
|
||||||
result_list = []
|
result_list = []
|
||||||
for task_key in group_list:
|
for task_key in group_list:
|
||||||
task = signing.SignedPackage.loads(broker.cache.get(task_key))
|
task = SignedPackage.loads(broker.cache.get(task_key))
|
||||||
if task['success'] or failures:
|
if task['success'] or failures:
|
||||||
result_list.append(task['result'])
|
result_list.append(task['result'])
|
||||||
return result_list
|
return result_list
|
||||||
if (time.time() - start) * 1000 >= wait >= 0:
|
if (time() - start) * 1000 >= wait >= 0:
|
||||||
break
|
break
|
||||||
time.sleep(0.01)
|
sleep(0.01)
|
||||||
|
|
||||||
|
|
||||||
def fetch(task_id, wait=0, cached=Conf.CACHED):
|
def fetch(task_id, wait=0, cached=Conf.CACHED):
|
||||||
@@ -205,14 +207,14 @@ def fetch(task_id, wait=0, cached=Conf.CACHED):
|
|||||||
"""
|
"""
|
||||||
if cached:
|
if cached:
|
||||||
return fetch_cached(task_id, wait)
|
return fetch_cached(task_id, wait)
|
||||||
start = time.time()
|
start = time()
|
||||||
while True:
|
while True:
|
||||||
t = Task.get_task(task_id)
|
t = Task.get_task(task_id)
|
||||||
if t:
|
if t:
|
||||||
return t
|
return t
|
||||||
if (time.time() - start) * 1000 >= wait >= 0:
|
if (time() - start) * 1000 >= wait >= 0:
|
||||||
break
|
break
|
||||||
time.sleep(0.01)
|
sleep(0.01)
|
||||||
|
|
||||||
|
|
||||||
def fetch_cached(task_id, wait=0, broker=None):
|
def fetch_cached(task_id, wait=0, broker=None):
|
||||||
@@ -221,11 +223,11 @@ def fetch_cached(task_id, wait=0, broker=None):
|
|||||||
"""
|
"""
|
||||||
if not broker:
|
if not broker:
|
||||||
broker = get_broker()
|
broker = get_broker()
|
||||||
start = time.time()
|
start = time()
|
||||||
while True:
|
while True:
|
||||||
r = broker.cache.get('{}:{}'.format(broker.list_key, task_id))
|
r = broker.cache.get('{}:{}'.format(broker.list_key, task_id))
|
||||||
if r:
|
if r:
|
||||||
task = signing.SignedPackage.loads(r)
|
task = SignedPackage.loads(r)
|
||||||
t = Task(id=task['id'],
|
t = Task(id=task['id'],
|
||||||
name=task['name'],
|
name=task['name'],
|
||||||
func=task['func'],
|
func=task['func'],
|
||||||
@@ -237,9 +239,9 @@ def fetch_cached(task_id, wait=0, broker=None):
|
|||||||
result=task['result'],
|
result=task['result'],
|
||||||
success=task['success'])
|
success=task['success'])
|
||||||
return t
|
return t
|
||||||
if (time.time() - start) * 1000 >= wait >= 0:
|
if (time() - start) * 1000 >= wait >= 0:
|
||||||
break
|
break
|
||||||
time.sleep(0.01)
|
sleep(0.01)
|
||||||
|
|
||||||
|
|
||||||
def fetch_group(group_id, failures=True, wait=0, count=None, cached=Conf.CACHED):
|
def fetch_group(group_id, failures=True, wait=0, count=None, cached=Conf.CACHED):
|
||||||
@@ -253,19 +255,19 @@ def fetch_group(group_id, failures=True, wait=0, count=None, cached=Conf.CACHED)
|
|||||||
"""
|
"""
|
||||||
if cached:
|
if cached:
|
||||||
return fetch_group_cached(group_id, failures, wait, count)
|
return fetch_group_cached(group_id, failures, wait, count)
|
||||||
start = time.time()
|
start = time()
|
||||||
if count:
|
if count:
|
||||||
while True:
|
while True:
|
||||||
if count_group(group_id) == count or wait and (time.time() - start) * 1000 >= wait >= 0:
|
if count_group(group_id) == count or wait and (time() - start) * 1000 >= wait >= 0:
|
||||||
break
|
break
|
||||||
time.sleep(0.01)
|
sleep(0.01)
|
||||||
while True:
|
while True:
|
||||||
r = Task.get_task_group(group_id, failures)
|
r = Task.get_task_group(group_id, failures)
|
||||||
if r:
|
if r:
|
||||||
return r
|
return r
|
||||||
if (time.time() - start) * 1000 >= wait >= 0:
|
if (time() - start) * 1000 >= wait >= 0:
|
||||||
break
|
break
|
||||||
time.sleep(0.01)
|
sleep(0.01)
|
||||||
|
|
||||||
|
|
||||||
def fetch_group_cached(group_id, failures=True, wait=0, count=None, broker=None):
|
def fetch_group_cached(group_id, failures=True, wait=0, count=None, broker=None):
|
||||||
@@ -274,18 +276,18 @@ def fetch_group_cached(group_id, failures=True, wait=0, count=None, broker=None)
|
|||||||
"""
|
"""
|
||||||
if not broker:
|
if not broker:
|
||||||
broker = get_broker()
|
broker = get_broker()
|
||||||
start = time.time()
|
start = time()
|
||||||
if count:
|
if count:
|
||||||
while True:
|
while True:
|
||||||
if count_group_cached(group_id) == count or wait and (time.time() - start) * 1000 >= wait >= 0:
|
if count_group_cached(group_id) == count or wait and (time() - start) * 1000 >= wait >= 0:
|
||||||
break
|
break
|
||||||
time.sleep(0.01)
|
sleep(0.01)
|
||||||
while True:
|
while True:
|
||||||
group_list = broker.cache.get('{}:{}:keys'.format(broker.list_key, group_id))
|
group_list = broker.cache.get('{}:{}:keys'.format(broker.list_key, group_id))
|
||||||
if group_list:
|
if group_list:
|
||||||
task_list = []
|
task_list = []
|
||||||
for task_key in group_list:
|
for task_key in group_list:
|
||||||
task = signing.SignedPackage.loads(broker.cache.get(task_key))
|
task = SignedPackage.loads(broker.cache.get(task_key))
|
||||||
if task['success'] or failures:
|
if task['success'] or failures:
|
||||||
t = Task(id=task['id'],
|
t = Task(id=task['id'],
|
||||||
name=task['name'],
|
name=task['name'],
|
||||||
@@ -300,9 +302,9 @@ def fetch_group_cached(group_id, failures=True, wait=0, count=None, broker=None)
|
|||||||
success=task['success'])
|
success=task['success'])
|
||||||
task_list.append(t)
|
task_list.append(t)
|
||||||
return task_list
|
return task_list
|
||||||
if (time.time() - start) * 1000 >= wait >= 0:
|
if (time() - start) * 1000 >= wait >= 0:
|
||||||
break
|
break
|
||||||
time.sleep(0.01)
|
sleep(0.01)
|
||||||
|
|
||||||
|
|
||||||
def count_group(group_id, failures=False, cached=Conf.CACHED):
|
def count_group(group_id, failures=False, cached=Conf.CACHED):
|
||||||
@@ -332,7 +334,7 @@ def count_group_cached(group_id, failures=False, broker=None):
|
|||||||
return len(group_list)
|
return len(group_list)
|
||||||
failure_count = 0
|
failure_count = 0
|
||||||
for task_key in group_list:
|
for task_key in group_list:
|
||||||
task = signing.SignedPackage.loads(broker.cache.get(task_key))
|
task = SignedPackage.loads(broker.cache.get(task_key))
|
||||||
if not task['success']:
|
if not task['success']:
|
||||||
failure_count += 1
|
failure_count += 1
|
||||||
return failure_count
|
return failure_count
|
||||||
@@ -405,7 +407,7 @@ def async_iter(func, args_iter, **kwargs):
|
|||||||
options['cached'] = True
|
options['cached'] = True
|
||||||
# save the original arguments
|
# save the original arguments
|
||||||
broker = options['broker']
|
broker = options['broker']
|
||||||
broker.cache.set('{}:{}:args'.format(broker.list_key, iter_group), signing.SignedPackage.dumps(args_iter))
|
broker.cache.set('{}:{}:args'.format(broker.list_key, iter_group), SignedPackage.dumps(args_iter))
|
||||||
for args in args_iter:
|
for args in args_iter:
|
||||||
if type(args) is not tuple:
|
if type(args) is not tuple:
|
||||||
args = (args,)
|
args = (args,)
|
||||||
@@ -671,13 +673,17 @@ class Async(object):
|
|||||||
|
|
||||||
|
|
||||||
def _sync(pack):
|
def _sync(pack):
|
||||||
|
# Python 2.6 is unable to handle this import on top of the file
|
||||||
|
# because it creates a circular dependency between tasks and cluster
|
||||||
|
from django_q.cluster import worker, monitor
|
||||||
|
|
||||||
"""Simulate a package travelling through the cluster."""
|
"""Simulate a package travelling through the cluster."""
|
||||||
task_queue = Queue()
|
task_queue = Queue()
|
||||||
result_queue = Queue()
|
result_queue = Queue()
|
||||||
task = signing.SignedPackage.loads(pack)
|
task = SignedPackage.loads(pack)
|
||||||
task_queue.put(task)
|
task_queue.put(task)
|
||||||
task_queue.put('STOP')
|
task_queue.put('STOP')
|
||||||
cluster.worker(task_queue, result_queue, Value('f', -1))
|
worker(task_queue, result_queue, Value('f', -1))
|
||||||
result_queue.put('STOP')
|
result_queue.put('STOP')
|
||||||
cluster.monitor(result_queue)
|
monitor(result_queue)
|
||||||
return task['id']
|
return task['id']
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ from django_q.tasks import fetch, fetch_group, async, result, result_group, coun
|
|||||||
from django_q.models import Task, Success
|
from django_q.models import Task, Success
|
||||||
from django_q.conf import Conf
|
from django_q.conf import Conf
|
||||||
from django_q.status import Stat
|
from django_q.status import Stat
|
||||||
from django_q.brokers import get_broker
|
from django_q.brokers import get_broker, Broker
|
||||||
from django_q.tests.tasks import multiply
|
from django_q.tests.tasks import multiply
|
||||||
from django_q.queues import Queue
|
from django_q.queues import Queue
|
||||||
|
|
||||||
@@ -379,6 +379,57 @@ def test_update_failed(broker):
|
|||||||
assert saved_task.success is True
|
assert saved_task.success is True
|
||||||
assert saved_task.result == 'result'
|
assert saved_task.result == 'result'
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_acknowledge_failure_override():
|
||||||
|
class VerifyAckMockBroker(Broker):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(VerifyAckMockBroker, self).__init__(*args, **kwargs)
|
||||||
|
self.acknowledgements = {}
|
||||||
|
|
||||||
|
def acknowledge(self, task_id):
|
||||||
|
count = self.acknowledgements.get(task_id, 0)
|
||||||
|
self.acknowledgements[task_id] = count + 1
|
||||||
|
|
||||||
|
tag = uuid()
|
||||||
|
task_fail_ack = {'id': tag[1],
|
||||||
|
'name': tag[0],
|
||||||
|
'ack_id': 'test_fail_ack_id',
|
||||||
|
'ack_failure': True,
|
||||||
|
'func': 'math.copysign',
|
||||||
|
'args': (1, -1),
|
||||||
|
'kwargs': {},
|
||||||
|
'started': timezone.now(),
|
||||||
|
'stopped': timezone.now(),
|
||||||
|
'success': False,
|
||||||
|
'result': None}
|
||||||
|
|
||||||
|
tag = uuid()
|
||||||
|
task_fail_no_ack = task_fail_ack.copy()
|
||||||
|
task_fail_no_ack.update({'id': tag[1],
|
||||||
|
'name': tag[0],
|
||||||
|
'ack_id': 'test_fail_no_ack_id'})
|
||||||
|
del task_fail_no_ack['ack_failure']
|
||||||
|
|
||||||
|
tag = uuid()
|
||||||
|
task_success_ack = task_fail_ack.copy()
|
||||||
|
task_success_ack.update({'id': tag[1],
|
||||||
|
'name': tag[0],
|
||||||
|
'ack_id': 'test_success_ack_id',
|
||||||
|
'success': True,})
|
||||||
|
del task_success_ack['ack_failure']
|
||||||
|
|
||||||
|
result_queue = Queue()
|
||||||
|
result_queue.put(task_fail_ack)
|
||||||
|
result_queue.put(task_fail_no_ack)
|
||||||
|
result_queue.put(task_success_ack)
|
||||||
|
result_queue.put('STOP')
|
||||||
|
broker = VerifyAckMockBroker(list_key='key')
|
||||||
|
|
||||||
|
monitor(result_queue, broker)
|
||||||
|
|
||||||
|
assert broker.acknowledgements.get('test_fail_ack_id') == 1
|
||||||
|
assert broker.acknowledgements.get('test_fail_no_ack_id') is None
|
||||||
|
assert broker.acknowledgements.get('test_success_ack_id') == 1
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def assert_result(task):
|
def assert_result(task):
|
||||||
|
|||||||
@@ -20,9 +20,13 @@ Broker
|
|||||||
The broker collects task packages from the django instances and queues them for pick up by a cluster.
|
The broker collects task packages from the django instances and queues them for pick up by a cluster.
|
||||||
If the broker supports message receipts, it will keep a copy of the tasks around until a cluster acknowledges the processing of the task.
|
If the broker supports message receipts, it will keep a copy of the tasks around until a cluster acknowledges the processing of the task.
|
||||||
Otherwise it is put back in the queue after a timeout period. This ensure at-least-once delivery.
|
Otherwise it is put back in the queue after a timeout period. This ensure at-least-once delivery.
|
||||||
Note that even if the task errors when processed by the cluster, this is considered a successful delivery.
|
|
||||||
Most failed deliveries will be the result of a worker or the cluster crashing before the task was saved.
|
Most failed deliveries will be the result of a worker or the cluster crashing before the task was saved.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
When the :ref:`ack_failures` option is set to ``False`` (the default), a task is
|
||||||
|
considered a failed delivery when it raises an ``Exception``. Set
|
||||||
|
this option to ``True`` to acknowledge failed tasks as successful.
|
||||||
|
|
||||||
Pusher
|
Pusher
|
||||||
""""""
|
""""""
|
||||||
|
|
||||||
|
|||||||
@@ -59,6 +59,13 @@ timeout
|
|||||||
The number of seconds a worker is allowed to spend on a task before it's terminated. Defaults to ``None``, meaning it will never time out.
|
The number of seconds a worker is allowed to spend on a task before it's terminated. Defaults to ``None``, meaning it will never time out.
|
||||||
Set this to something that makes sense for your project. Can be overridden for individual tasks.
|
Set this to something that makes sense for your project. Can be overridden for individual tasks.
|
||||||
|
|
||||||
|
.. _ack_failures:
|
||||||
|
|
||||||
|
ack_failures
|
||||||
|
~~~~~~~~~~~~
|
||||||
|
|
||||||
|
When set to ``True``, also acknowledge unsuccessful tasks. This causes failed tasks to be considered as successful deliveries, thereby removing them from the task queue. Can also be set per-task by passing the ``ack_failure`` option to :func:`async`. Defaults to ``False``.
|
||||||
|
|
||||||
.. _retry:
|
.. _retry:
|
||||||
|
|
||||||
retry
|
retry
|
||||||
|
|||||||
@@ -54,6 +54,10 @@ timeout
|
|||||||
"""""""
|
"""""""
|
||||||
Overrides the cluster's timeout setting for this task.
|
Overrides the cluster's timeout setting for this task.
|
||||||
|
|
||||||
|
ack_failure
|
||||||
|
"""""""""""
|
||||||
|
Overrides the cluster's :ref:`ack_failures` setting for this task.
|
||||||
|
|
||||||
sync
|
sync
|
||||||
""""
|
""""
|
||||||
Simulates a task execution synchronously. Useful for testing.
|
Simulates a task execution synchronously. Useful for testing.
|
||||||
@@ -244,6 +248,7 @@ Reference
|
|||||||
:param str group: An optional group identifier
|
:param str group: An optional group identifier
|
||||||
:param int timeout: Overrides global cluster :ref:`timeout`.
|
:param int timeout: Overrides global cluster :ref:`timeout`.
|
||||||
:param bool save: Overrides global save setting for this task.
|
:param bool save: Overrides global save setting for this task.
|
||||||
|
:param bool ack_failure: Overrides the global :ref:`ack_failures` setting for this task.
|
||||||
:param bool sync: If set to True, async will simulate a task execution
|
:param bool sync: If set to True, async will simulate a task execution
|
||||||
:param cached: Output the result to the cache backend. Bool or timeout in seconds
|
:param cached: Output the result to the cache backend. Bool or timeout in seconds
|
||||||
:param broker: Optional broker connection from :func:`brokers.get_broker`
|
:param broker: Optional broker connection from :func:`brokers.get_broker`
|
||||||
|
|||||||
Reference in New Issue
Block a user