芹菜重试消息保留在同一工作人员中

时间:2019-01-27 12:05:43

标签: python celery

我的内心印象是,如果一位芹菜工人得到一项任务,并且该任务被重试-它保留在该工人的记忆中(带有eta),并且不会返回队列。 结果是,如果重试了芹菜任务,而工作人员正忙于处理其他任务,并且任务eta到达,则必须等到完成其他任务的处理。

我尝试在文档中查找与我记得的内容相符的内容,但找不到任何内容。

我尝试检查一下是创建两个任务。

@app.task(bind=True, name='task_that_holds_worker', rate_limit='4/m',
          default_retry_delay=5 * 60,
          max_retries=int(60 * 60 * 24 * 1 / (60 * 5)))
def task_that_holds_worker(self, *args, **kwargs):
    import time
    time.sleep(50000)

@app.task(bind=True, name='retried_task', rate_limit='2/m',
          default_retry_delay=10 * 60,
          max_retries=int(60 * 60 * 24 * 1 / (60 * 10)))
def retried_task(self, *args, **kwargs):
    self.retry()

最简单的任务,只是检查一个任务是否正忙于其他任务-重试的任务没有被其他工作人员处理。

然后,我启动了一名工作人员-并通过以下方式触发了这两项任务:

from some_app import tasks
from some_app.celery_app import app

current_app = app.tasks

async_result = tasks.retried_task.delay()

import time
time.sleep(20)

async_result = tasks.task_that_holds_worker.delay()

工作人员处理了重试的任务,然后重试了它, 然后转移到睡觉的任务。 然后,我启动了另一个工作程序,可以看到它没有执行“重试”任务,只有第一个工作程序。

每位被解雇的工人都遭到--prefetch-multiplier=1 --concurrency=1 我的复制方式有问题吗? 还是这是芹菜重试任务的行为方式?

谢谢!

  • 芹菜:4.1.2
  • Python:3.6.2
  • Rabbitmq图片:rabbitmq:3.6.9-管理

2 个答案:

答案 0 :(得分:0)

复制方式有误。除非您有特殊的经纪人,否则celery会始终将任务重试请求重新排队给经纪人。工作程序不会保留他们尝试执行的任务的任何内存,并且重试请求中没有添加任何数据,这些数据允许celery将任务请求路由回同一工作程序。不能保证或保证同一名工人将重试以前见过的任务。您可以在celery/app.task.py

的芹菜代码中对此进行确认


# get the signature of the task as called
S = self.signature_from_request(
    request, args, kwargs,
    countdown=countdown, eta=eta, retries=retries,
    **options
)

if max_retries is not None and retries > max_retries: if exc: # On Py3: will augment any current exception with # the exc' argument provided (raise exc from orig) raise_with_context(exc) raise self.MaxRetriesExceededError( "Can't retry {0}[{1}] args:{2} kwargs:{3}".format( self.name, request.id, S.args, S.kwargs))
ret = Retry(exc=exc, when=eta or countdown) if is_eager: # if task was executed eagerly using apply(), # then the retry must also be executed eagerly. S.apply().get() if throw: raise ret return ret
try: S.apply_async() except Exception as exc: raise Reject(exc, requeue=False) if throw: raise ret return ret

我已经加粗了一部分,您可以在其中看到重试的工作原理。 Celery获取任务请求签名(包括任务名称和任务参数,并设置eta,倒数和重试)。然后celery会简单地调用apply_async,这将在后台将新任务请求排队到代理。

您的样本没有用,因为芹菜工人通常会从经纪人那里提取多个任务请求,因此可能发生的情况是第一个工人在第二个工人上线之前就从经纪人那里抢走了任务。

答案 1 :(得分:0)

似乎这是eta任务的问题。第一个可用的工作人员递减计数,直到任务eta并没有将其释放回队列。 (预取计数增加且被忽略)

https://github.com/celery/celery/issues/2541