|
@@ -7,7 +7,6 @@ from itertools import imap
|
|
|
|
|
|
from celery import states
|
|
|
from celery.app import app_or_default
|
|
|
-from celery.datastructures import PositionQueue
|
|
|
from celery.exceptions import TimeoutError
|
|
|
from celery.registry import _unpickle_task
|
|
|
from celery.utils.compat import any, all
|
|
@@ -61,11 +60,21 @@ class BaseAsyncResult(object):
|
|
|
self.app.control.revoke(self.task_id, connection=connection,
|
|
|
connect_timeout=connect_timeout)
|
|
|
|
|
|
- def wait(self, timeout=None):
|
|
|
+ def wait(self, timeout=None, propagate=True, interval=0.5):
|
|
|
"""Wait for task, and return the result.
|
|
|
|
|
|
+ .. warning::
|
|
|
+
|
|
|
+ Waiting for subtasks may lead to deadlocks.
|
|
|
+ Please read :ref:`task-synchronous-subtasks`.
|
|
|
+
|
|
|
:keyword timeout: How long to wait, in seconds, before the
|
|
|
operation times out.
|
|
|
+ :keyword propagate: Re-raise exception if the task failed.
|
|
|
+ :keyword interval: Time to wait (in seconds) before retrying to
|
|
|
+ retrieve the result. Note that this does not have any effect
|
|
|
+ when using the AMQP result store backend, as it does not
|
|
|
+ use polling.
|
|
|
|
|
|
:raises celery.exceptions.TimeoutError: if `timeout` is not
|
|
|
:const:`None` and the result does not arrive within `timeout`
|
|
@@ -75,7 +84,9 @@ class BaseAsyncResult(object):
|
|
|
be re-raised.
|
|
|
|
|
|
"""
|
|
|
- return self.backend.wait_for(self.task_id, timeout=timeout)
|
|
|
+ return self.backend.wait_for(self.task_id, timeout=timeout,
|
|
|
+ propagate=propagate,
|
|
|
+ interval=interval)
|
|
|
|
|
|
def get(self, timeout=None):
|
|
|
"""Alias to :meth:`wait`."""
|
|
@@ -319,24 +330,56 @@ class TaskSetResult(object):
|
|
|
elif result.status in states.PROPAGATE_STATES:
|
|
|
raise result.result
|
|
|
|
|
|
- def join(self, timeout=None, propagate=True):
|
|
|
+ def join(self, timeout=None, propagate=True, interval=0.5):
|
|
|
"""Gather the results of all tasks in the taskset,
|
|
|
and returns a list ordered by the order of the set.
|
|
|
|
|
|
+ .. note::
|
|
|
+
|
|
|
+ This can be an very expensive operation on result store
|
|
|
+ backends that must resort to polling (e.g. database).
|
|
|
+
|
|
|
+ You should consider using :meth:`join_native` if your backends
|
|
|
+ supports it.
|
|
|
+
|
|
|
+ .. warning::
|
|
|
+
|
|
|
+ Waiting for subtasks may lead the deadlocks.
|
|
|
+ Please see :ref:`task-synchronous-subtasks`.
|
|
|
+
|
|
|
:keyword timeout: The number of seconds to wait for results before
|
|
|
the operation times out.
|
|
|
|
|
|
:keyword propagate: If any of the subtasks raises an exception, the
|
|
|
exception will be reraised.
|
|
|
|
|
|
+ :keyword interval: Time to wait (in seconds) before retrying to
|
|
|
+ retrieve a result from the set. Note that this
|
|
|
+ does not have any effect when using the AMQP
|
|
|
+ result store backend, as it does not use polling.
|
|
|
+
|
|
|
:raises celery.exceptions.TimeoutError: if `timeout` is not
|
|
|
:const:`None` and the operation takes longer than `timeout`
|
|
|
seconds.
|
|
|
|
|
|
"""
|
|
|
-
|
|
|
time_start = time.time()
|
|
|
- results = PositionQueue(length=self.total)
|
|
|
+ remaining = None
|
|
|
+
|
|
|
+ results = []
|
|
|
+ for subtask in self.subtasks:
|
|
|
+ remaining = None
|
|
|
+ if timeout:
|
|
|
+ remaining = timeout - (time.time() - time_start)
|
|
|
+ if remaining <= 0.0:
|
|
|
+ raise TimeoutError("join operation timed out")
|
|
|
+ results.append(subtask.wait(timeout=remaining,
|
|
|
+ propagate=propagate,
|
|
|
+ interval=interval))
|
|
|
+ return results
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
|
|
|
while True:
|
|
|
for position, pending_result in enumerate(self.subtasks):
|
|
@@ -371,7 +414,7 @@ class TaskSetResult(object):
|
|
|
|
|
|
"""
|
|
|
backend = self.subtasks[0].backend
|
|
|
- results = PositionQueue(length=self.total)
|
|
|
+ results = [None for _ in xrange(len(self.subtasks))]
|
|
|
|
|
|
ids = [subtask.task_id for subtask in self.subtasks]
|
|
|
states = dict(backend.get_many(ids, timeout=timeout))
|
|
@@ -426,12 +469,14 @@ class EagerResult(BaseAsyncResult):
|
|
|
"""Returns :const:`True` if the task has been executed."""
|
|
|
return True
|
|
|
|
|
|
- def wait(self, timeout=None):
|
|
|
+ def wait(self, timeout=None, propagate=True, **kwargs):
|
|
|
"""Wait until the task has been executed and return its result."""
|
|
|
if self.state == states.SUCCESS:
|
|
|
return self.result
|
|
|
elif self.state in states.PROPAGATE_STATES:
|
|
|
- raise self.result
|
|
|
+ if propagate:
|
|
|
+ raise self.result
|
|
|
+ return self.result
|
|
|
|
|
|
def revoke(self):
|
|
|
self._state = states.REVOKED
|