我有一个Celery任务,它接收来自SQS队列的消息并尝试运行它。如果失败,则应该每10秒重试至少144次。我认为正在发生的是它失败并重新进入队列,同时它创建了一个新的,重复它为2.这两个再次失败并按照相同的模式创建2个新的并成为4个消息总。因此,如果我让它运行一段时间,队列就会被堵塞。
我没有得到的是在不重复的情况下重试它的正确方法。以下是重试的代码。请看看有人可以在这里指导我。
from celery import shared_task
from celery.exceptions import MaxRetriesExceededError
@shared_task
def send_br_update(bgc_id, xref_id, user_id, event):
from myapp.models.mappings import BGC
try:
bgc = BGC.objects.get(pk=bgc_id)
return bgc.send_br_update(user_id, event)
except BGC.DoesNotExist:
pass
except MaxRetriesExceededError:
pass
except Exception as exc:
# retry every 10 minutes for at least 24 hours
raise send_br_update.retry(exc=exc, countdown=600, max_retries=144)
更新 对此问题的更多解释......
用户在我的数据库中创建一个对象。其他用户对该对象进行操作,当他们更改该对象的状态时,我的代码会发出信号。然后,信号处理程序启动芹菜任务,这意味着它连接到所需的SQS队列并将消息提交给队列。运行工作程序的芹菜服务器会看到新消息并尝试执行该任务。这是它失败的地方,并且重试逻辑进入。
根据celery文档retry a task,我们需要做的就是用countdown和/或max_retries引发self.retry()调用。如果芹菜任务引发异常,则认为是失败的。我不确定SQS如何处理这个问题。我所知道的是,一个任务失败,队列中有两个,两个都失败,然后队列中有4个等等......
答案 0 :(得分:1)
这不是芹菜,也不是SQS问题。 真正的问题是工作流,即您向MQ服务发送消息并处理导致重复的方式。使用任何其他MQ服务您将面临同样的问题。
想象一下你的流程
因此,如果任务继续失败,它将保持乘法,2,4,8,16,32 ....
如果芹菜脚本意味着“重新创建失败的任务并发送到消息队列”,您需要确保这些消息只能读取ONCE。 **即使任务失败,您必须在已经读过1次后丢弃任务消息。 **
至少有两种方法可以做到这一点,选择一种方法。
您可能更喜欢方法2,因为方法1要求您将芹菜配置为“消费”(读取和删除)尽快它读取消息,这不是很实用。 (并且必须确保在为失败的任务创建新消息之前将其删除) 这个死信队列是一种让你检查芹菜CRASH,即已被读过但未被消费(删除)的消息的方法,意味着程序在某处停止。
答案 1 :(得分:0)
这可能有点晚了,我为Celery + SQS编写了一个补丁修补程序。
您可以看到它如何在此存储库中实现
https://github.com/galCohen88/celery_sqs_retry_policy/blob/master/svc/celery.py