def test_on_retry(self): tw = TaskRequest(mytask.name, uuid(), [1], {"f": "x"}) tw.eventer = MockEventDispatcher() try: raise RetryTaskError("foo", KeyError("moofoobar")) except: einfo = ExceptionInfo(sys.exc_info()) tw.on_failure(einfo) self.assertIn("task-retried", tw.eventer.sent)
def test_worker_task_trace_handle_retry(self): from celery.exceptions import RetryTaskError tid = uuid() w = WorkerTaskTrace(mytask.name, tid, [4], {}) type_, value_, tb_ = self.create_exception(ValueError("foo")) type_, value_, tb_ = self.create_exception( RetryTaskError(str(value_), exc=value_)) w._store_errors = False w.handle_retry(value_, type_, tb_, "") self.assertEqual(mytask.backend.get_status(tid), states.PENDING) w._store_errors = True w.handle_retry(value_, type_, tb_, "") self.assertEqual(mytask.backend.get_status(tid), states.RETRY)
def test_worker_task_trace_handle_retry(self): from celery.exceptions import RetryTaskError tid = uuid() mytask.request.update({"id": tid}) try: _, value_, _ = self.create_exception(ValueError("foo")) einfo = self.create_exception( RetryTaskError(str(value_), exc=value_)) w = TraceInfo(states.RETRY, einfo[1], einfo) w.handle_retry(mytask, store_errors=False) self.assertEqual(mytask.backend.get_status(tid), states.PENDING) w.handle_retry(mytask, store_errors=True) self.assertEqual(mytask.backend.get_status(tid), states.RETRY) finally: mytask.request.clear()
def test_on_retry(self): tw = TaskRequest(mytask.name, uuid(), [1], {'f': 'x'}, app=self.app) tw.eventer = MockEventDispatcher() try: raise RetryTaskError('foo', KeyError('moofoobar')) except: einfo = ExceptionInfo() tw.on_failure(einfo) self.assertIn('task-retried', tw.eventer.sent) prev, module._does_info = module._does_info, False try: tw.on_failure(einfo) finally: module._does_info = prev einfo.internal = True tw.on_failure(einfo)
def test_on_retry(self): tw = TaskRequest(mytask.name, uuid(), [1], {"f": "x"}) tw.eventer = MockEventDispatcher() try: raise RetryTaskError("foo", KeyError("moofoobar")) except: einfo = ExceptionInfo() tw.on_failure(einfo) self.assertIn("task-retried", tw.eventer.sent) prev, module._does_info = module._does_info, False try: tw.on_failure(einfo) finally: module._does_info = prev einfo.internal = True tw.on_failure(einfo)
def test_worker_task_trace_handle_retry(self): from celery.exceptions import RetryTaskError tid = uuid() mytask.request.update({"id": tid}) try: raise ValueError("foo") except Exception, exc: try: raise RetryTaskError(str(exc), exc=exc) except RetryTaskError, exc: w = TraceInfo(states.RETRY, exc) w.handle_retry(mytask, store_errors=False) self.assertEqual(mytask.backend.get_status(tid), states.PENDING) w.handle_retry(mytask, store_errors=True) self.assertEqual(mytask.backend.get_status(tid), states.RETRY)
def test_worker_task_trace_handle_retry(self): from celery.exceptions import RetryTaskError tid = uuid() mytask.push_request(id=tid) try: raise ValueError('foo') except Exception as exc: try: raise RetryTaskError(str(exc), exc=exc) except RetryTaskError as exc: w = TraceInfo(states.RETRY, exc) w.handle_retry(mytask, store_errors=False) self.assertEqual(mytask.backend.get_status(tid), states.PENDING) w.handle_retry(mytask, store_errors=True) self.assertEqual(mytask.backend.get_status(tid), states.RETRY) finally: mytask.pop_request()
def test_trace_RetryTaskError(self): exc = RetryTaskError("foo", "bar") _, info = trace(raises, (exc, ), {}) self.assertEqual(info.state, states.RETRY) self.assertIs(info.retval, exc)
def test_retry_task_error(self): try: raise Exception('foo') except Exception as exc: ret = RetryTaskError('Retrying task', exc) self.assertEqual(ret.exc, exc)
def test_when_datetime(self): x = RetryTaskError('foo', KeyError(), when=datetime.utcnow()) self.assertTrue(x.humanize())
def test_retry_task_error(self): try: raise Exception("foo") except Exception, exc: ret = RetryTaskError("Retrying task", exc)
def retry(self, args=None, kwargs=None, exc=None, throw=True, eta=None, countdown=None, max_retries=None, **options): """Retry the task. :param args: Positional arguments to retry with. :param kwargs: Keyword arguments to retry with. :keyword exc: Optional exception to raise instead of :exc:`~celery.exceptions.MaxRetriesExceededError` when the max restart limit has been exceeded. :keyword countdown: Time in seconds to delay the retry for. :keyword eta: Explicit time and date to run the retry at (must be a :class:`~datetime.datetime` instance). :keyword max_retries: If set, overrides the default retry limit. :keyword timeout: If set, overrides the default timeout. :keyword soft_timeout: If set, overrides the default soft timeout. :keyword \*\*options: Any extra options to pass on to meth:`apply_async`. :keyword throw: If this is :const:`False`, do not raise the :exc:`~celery.exceptions.RetryTaskError` exception, that tells the worker to mark the task as being retried. Note that this means the task will be marked as failed if the task raises an exception, or successful if it returns. :raises celery.exceptions.RetryTaskError: To tell the worker that the task has been re-sent for retry. This always happens, unless the `throw` keyword argument has been explicitly set to :const:`False`, and is considered normal operation. **Example** .. code-block:: python >>> @task() >>> def tweet(auth, message): ... twitter = Twitter(oauth=auth) ... try: ... twitter.post_status_update(message) ... except twitter.FailWhale as exc: ... # Retry in 5 minutes. ... raise tweet.retry(countdown=60 * 5, exc=exc) Although the task will never return above as `retry` raises an exception to notify the worker, we use `return` in front of the retry to convey that the rest of the block will not be executed. """ request = self.request max_retries = self.max_retries if max_retries is None else max_retries args = request.args if args is None else args kwargs = request.kwargs if kwargs is None else kwargs delivery_info = request.delivery_info # Not in worker or emulated by (apply/always_eager), # so just raise the original exception. if request.called_directly: maybe_reraise() raise exc or RetryTaskError('Task can be retried', None) if delivery_info: options.setdefault('exchange', delivery_info.get('exchange')) options.setdefault('routing_key', delivery_info.get('routing_key')) options.setdefault('expires', request.expires) if not eta and countdown is None: countdown = self.default_retry_delay options.update({ 'retries': request.retries + 1, 'task_id': request.id, 'countdown': countdown, 'eta': eta, 'link': request.callbacks, 'link_error': request.errbacks }) if max_retries is not None and options['retries'] > max_retries: if exc: maybe_reraise() raise self.MaxRetriesExceededError( "Can't retry {0}[{1}] args:{2} kwargs:{3}".format( self.name, options['task_id'], args, kwargs)) # If task was executed eagerly using apply(), # then the retry must also be executed eagerly. if request.is_eager: self.apply(args=args, kwargs=kwargs, **options).get() else: self.apply_async(args=args, kwargs=kwargs, **options) ret = RetryTaskError(exc=exc, when=eta or countdown) if throw: raise ret return ret
def test_task_status_retry(self): oexc, _ = catch_exception(KeyError("Resource not available")) exc, tb = catch_exception(RetryTaskError(str(oexc), oexc)) self.assertStatusForIs(states.RETRY, exc, tb)
def test_pickleable(self): x = RetryTaskError('foo', KeyError(), when=datetime.utcnow()) self.assertTrue(pickle.loads(pickle.dumps(x)))
def test_retry_task_error(self): try: raise Exception("foo") except Exception, exc: ret = RetryTaskError("Retrying task", exc) self.assertEqual(ret.exc, exc)
def retry(self, args=None, kwargs=None, exc=None, throw=True, eta=None, countdown=None, max_retries=None, **options): """Retry the task. :param args: Positional arguments to retry with. :param kwargs: Keyword arguments to retry with. :keyword exc: Optional exception to raise instead of :exc:`~celery.exceptions.MaxRetriesExceededError` when the max restart limit has been exceeded. :keyword countdown: Time in seconds to delay the retry for. :keyword eta: Explicit time and date to run the retry at (must be a :class:`~datetime.datetime` instance). :keyword max_retries: If set, overrides the default retry limit. :keyword \*\*options: Any extra options to pass on to meth:`apply_async`. :keyword throw: If this is :const:`False`, do not raise the :exc:`~celery.exceptions.RetryTaskError` exception, that tells the worker to mark the task as being retried. Note that this means the task will be marked as failed if the task raises an exception, or successful if it returns. :raises celery.exceptions.RetryTaskError: To tell the worker that the task has been re-sent for retry. This always happens, unless the `throw` keyword argument has been explicitly set to :const:`False`, and is considered normal operation. **Example** .. code-block:: python >>> @task >>> def tweet(auth, message): ... twitter = Twitter(oauth=auth) ... try: ... twitter.post_status_update(message) ... except twitter.FailWhale, exc: ... # Retry in 5 minutes. ... return tweet.retry(countdown=60 * 5, exc=exc) Although the task will never return above as `retry` raises an exception to notify the worker, we use `return` in front of the retry to convey that the rest of the block will not be executed. """ request = self.request if max_retries is None: max_retries = self.max_retries if args is None: args = request.args if kwargs is None: kwargs = request.kwargs delivery_info = request.delivery_info if delivery_info: options.setdefault("exchange", delivery_info.get("exchange")) options.setdefault("routing_key", delivery_info.get("routing_key")) if not eta and countdown is None: countdown = self.default_retry_delay options.update({"retries": request.retries + 1, "task_id": request.id, "countdown": countdown, "eta": eta}) if max_retries is not None and options["retries"] > max_retries: raise exc or self.MaxRetriesExceededError( "Can't retry %s[%s] args:%s kwargs:%s" % ( self.name, options["task_id"], args, kwargs)) # If task was executed eagerly using apply(), # then the retry must also be executed eagerly. if request.is_eager: return self.apply(args=args, kwargs=kwargs, **options).get() self.apply_async(args=args, kwargs=kwargs, **options) if throw: raise RetryTaskError( eta and "Retry at %s" % (eta, ) or "Retry in %s secs." % (countdown, ), exc)
def retry(self, args=None, kwargs=None, exc=None, throw=True, eta=None, countdown=None, max_retries=None, **options): """Retry the task. :param args: Positional arguments to retry with. :param kwargs: Keyword arguments to retry with. :keyword exc: Custom exception to report when the max restart limit has been exceeded (default: :exc:`~celery.exceptions.MaxRetriesExceededError`). If this argument is set and retry is called while an exception was raised (``sys.exc_info()`` is set) it will attempt to reraise the current exception. If no exception was raised it will raise the ``exc`` argument provided. :keyword countdown: Time in seconds to delay the retry for. :keyword eta: Explicit time and date to run the retry at (must be a :class:`~datetime.datetime` instance). :keyword max_retries: If set, overrides the default retry limit. :keyword \*\*options: Any extra options to pass on to meth:`apply_async`. :keyword throw: If this is :const:`False`, do not raise the :exc:`~celery.exceptions.RetryTaskError` exception, that tells the worker to mark the task as being retried. Note that this means the task will be marked as failed if the task raises an exception, or successful if it returns. :raises celery.exceptions.RetryTaskError: To tell the worker that the task has been re-sent for retry. This always happens, unless the `throw` keyword argument has been explicitly set to :const:`False`, and is considered normal operation. **Example** .. code-block:: python >>> @task() >>> def tweet(auth, message): ... twitter = Twitter(oauth=auth) ... try: ... twitter.post_status_update(message) ... except twitter.FailWhale, exc: ... # Retry in 5 minutes. ... raise tweet.retry(countdown=60 * 5, exc=exc) Although the task will never return above as `retry` raises an exception to notify the worker, we use `return` in front of the retry to convey that the rest of the block will not be executed. """ request = self.request retries = request.retries + 1 max_retries = self.max_retries if max_retries is None else max_retries # Not in worker or emulated by (apply/always_eager), # so just raise the original exception. if request.called_directly: maybe_reraise() # raise orig stack if PyErr_Occurred raise exc or RetryTaskError('Task can be retried', None) if not eta and countdown is None: countdown = self.default_retry_delay S = self.subtask_from_request(request, args, kwargs, countdown=countdown, eta=eta, retries=retries, **options) if max_retries is not None and retries > max_retries: if exc: maybe_reraise() raise self.MaxRetriesExceededError( """Can't retry %s[%s] args:%s kwargs:%s""" % (self.name, request.id, S.args, S.kwargs)) # If task was executed eagerly using apply(), # then the retry must also be executed eagerly. S.apply().get() if request.is_eager else S.apply_async() ret = RetryTaskError(exc=exc, when=eta or countdown) if throw: raise ret return ret
def retry(self, args=None, kwargs=None, exc=None, throw=True, **options): """Retry the task. :param args: Positional arguments to retry with. :param kwargs: Keyword arguments to retry with. :keyword exc: Optional exception to raise instead of :exc:`~celery.exceptions.MaxRetriesExceededError` when the max restart limit has been exceeded. :keyword countdown: Time in seconds to delay the retry for. :keyword eta: Explicit time and date to run the retry at (must be a :class:`datetime.datetime` instance). :keyword \*\*options: Any extra options to pass on to meth:`apply_async`. See :func:`celery.execute.apply_async`. :keyword throw: If this is ``False``, do not raise the :exc:`~celery.exceptions.RetryTaskError` exception, that tells the worker to mark the task as being retried. Note that this means the task will be marked as failed if the task raises an exception, or successful if it returns. :raises celery.exceptions.RetryTaskError: To tell the worker that the task has been re-sent for retry. This always happens, unless the ``throw`` keyword argument has been explicitly set to ``False``, and is considered normal operation. Example >>> class TwitterPostStatusTask(Task): ... ... def run(self, username, password, message, **kwargs): ... twitter = Twitter(username, password) ... try: ... twitter.post_status(message) ... except twitter.FailWhale, exc: ... # Retry in 5 minutes. ... self.retry([username, password, message], kwargs, ... countdown=60 * 5, exc=exc) """ if not kwargs: raise TypeError( "kwargs argument to retries can't be empty. " "Task must accept **kwargs, see http://bit.ly/cAx3Bg") delivery_info = kwargs.pop("delivery_info", {}) options.setdefault("exchange", delivery_info.get("exchange")) options.setdefault("routing_key", delivery_info.get("routing_key")) options["retries"] = kwargs.pop("task_retries", 0) + 1 options["task_id"] = kwargs.pop("task_id", None) options["countdown"] = options.get("countdown", self.default_retry_delay) max_exc = exc or self.MaxRetriesExceededError( "Can't retry %s[%s] args:%s kwargs:%s" % ( self.name, options["task_id"], args, kwargs)) max_retries = self.max_retries if max_retries is not None and options["retries"] > max_retries: raise max_exc # If task was executed eagerly using apply(), # then the retry must also be executed eagerly. if kwargs.get("task_is_eager", False): result = self.apply(args=args, kwargs=kwargs, **options) if isinstance(result, EagerResult): return result.get() # propogates exceptions. return result self.apply_async(args=args, kwargs=kwargs, **options) if throw: message = "Retry in %d seconds." % options["countdown"] raise RetryTaskError(message, exc)