此代码在cron上运行。因此,我想立即更新对象的状态,这样,如果第二个cron在当前cron完成之前启动,这些对象就不会再次被拾取(这最终会在我的应用程序中发生(
# Grab all pending emails.
emails = delivery_que.objects.filter(status='PENDING')
emails.update(status='SENDING')
# Loop through the pending emails.
for email in emails:
当前的代码不起作用,因为在I.update((之后,我似乎不再能够访问这些对象。
这是我实现的变通方法:
# Grab all pending emails.
emails = delivery_que.objects.filter(status='PENDING')
emails.update(status='SENDING')
emails = delivery_que.objects.filter(status='SENDING')
# Loop through the pending emails.
for email in emails:
我还缺少其他更好的解决方案吗?我不想再查询数据库,而是从第一次查询中重新选择我应该已经可以访问的对象。
这里的问题是,您正在运行重叠的进程,并且在任何时间点都不知道对方在做什么。
简单的解决方案:
- 当作业启动时,请检查锁定记录。如果存在,请退出作业
- 添加一个锁定记录(到DB中的模型,触摸一个文件,等等(
- 处理作业
- 将锁定记录作为作业的最后一件事删除
稍微复杂一点的解决方案:
- 在作业开始时,将
PENDING
中的所有记录更新为该进程的唯一值(例如PROCESSING_<uuid>
( - 对具有该唯一值的记录运行更新
您也可以通过向模型中添加另一个字段来实现这一点,例如processing_id
,并检查该字段是否为空以及是否具有正确的PENDING
状态。
可能是最复杂的解决方案:
- 使过程幂等
我的意思是,它在同一条记录上运行两次并不重要。从你上面发布的代码来看,这实际上是真的,因为你所做的只是将状态更改为SENDING
,但我想有些代码你没有显示,用户会收到双重电子邮件。
如果你有代码来确保不会发送双重邮件,这就不是问题——对象可能会被处理两次,但它只会在第一次发送电子邮件。
在理想的世界里,所有像这样的过程都应该是幂等的,只是为了确保你永远不会遇到任何问题,如果有人在不应该的时候设法运行它。