我的django应用程序允许用户相互发送消息,我将一些最近的消息汇集在一起,并使用celery和redis通过电子邮件发送它们。
每次用户发送消息时,我都会向数据库添加一条消息,然后触发异步任务以汇集最近60秒内该用户的消息并将其作为电子邮件发送。
tasks.pushMessagePool.apply_async(args = (fromUser,), countdown = 60)
如果用户在接下来的60秒内发送了5条消息,那么我的假设是应创建5个任务,但只有第一个任务发送电子邮件,其他4个任务不执行任何操作。我实现了一个简单的锁定机制,以确保消息只被考虑一次,并确保数据库锁定。
@shared_task
def pushMessagePool(fromUser, ignore_result=True):
lockCode = randint(0,10**9)
data.models.Messages.objects.filter(fromUser = fromUser, locked=False).update(locked=True, lockCode = lockCode)
M = data.models.Messages.objects.filter(fromUser = fromUser, lockCode = lockCode)
sendEmail(M,lockCode)
通过这种设置,我偶尔会得到(~10%)重复。重复项将在彼此相差10ms内启动,并且它们具有不同的lockCodes。
为什么这种锁定机制不起作用?芹菜是指旧数据库快照吗?这没有任何意义。
答案 0 :(得分:0)
Djangojack,这是一个类似的问题?但对于SQS。我不确定它是否也适用于Redis?
创建SQS队列时,需要设置默认可见性 超时到某个时间,大于你期望的最长时间 任务运行。这是SQS将使所有人都看不到的消息的时间 交付给一个消费者后的其他消费者。我相信 默认为30秒。因此,如果任务需要超过30秒,SQS 将它传递给另一个消费者,因为它假定 第一个消费者死了,没有完成任务。
来自@ gustavo-ambrozio对this answer的评论。